The M3U8 file is an index file that contains N TS fragments to form a video file. Currently, it is widely used in live and on-demand. We downloaded a M3U8 video file, that is, we downloaded N TS sharded files, resulting in a lot of small fragments of video files in our mobile phone album. If it’s a shy video, it’s even more embarrassing. Delete all want to delete half a day, let alone want to copy out the M3U8 file, put on the computer to watch the appreciation. For example to give an example M3U8: tv2. Youkutv. Cc / 2020/04/14 /… , the index file is as follows:

#EXTM3U # ext-x-version :3 # ext-x-media-sequence :0 # ext-x-allow-cache :YES # ext-x-targetduration :19 #EXTINF:13.960000, Ts #EXTINF:10.320000, out001.ts #EXTINF:10.320000, out003.ts #EXTINF:10.320000, out003.ts #EXTINF:9.960000, out003.ts #EXTINF:10.320000, out003.ts #EXTINF:9.960000, Out004. Ts # EXTINF: 12.240000, out005 ts... . . #EXTINF:10.000000, out271.ts #EXTINF:6.960000, out272.ts # ext-x-endListCopy the code

There are 273 sharded files, you can use: github.com/JeffMony/M3… The script gets the current M3U8 index file. Download the video file below:

PD1824:/sdcard/Android/data/com.jeffmony.videodemo/files/Video/Download/a03663b3bd0a2fe6fcb8bb36b657cf80 $ ls local.m3u8  video_124.ts video_152.ts video_180.ts video_208.ts video_236.ts video_264.ts video_47.ts video_75.ts remote.m3u8 video_125.ts video_153.ts video_181.ts video_209.ts video_237.ts video_265.ts video_48.ts video_76.ts video_0.ts video_126.ts video_154.ts video_182.ts video_21.ts video_238.ts video_266.ts video_49.ts video_77.ts video_1.ts video_127.ts video_155.ts video_183.ts video_210.ts video_239.ts video_267.ts video_5.ts video_78.ts video_10.ts video_128.ts video_156.ts video_184.ts video_211.ts video_24.ts video_268.ts video_50.ts video_79.ts video_100.ts video_129.ts video_157.ts video_185.ts video_212.ts video_240.ts video_269.ts video_51.ts video_8.ts video_101.ts video_13.ts video_158.ts video_186.ts video_213.ts video_241.ts video_27.ts video_52.ts video_80.ts video_102.ts video_130.ts video_159.ts video_187.ts video_214.ts video_242.ts video_270.ts video_53.ts video_81.ts video_103.ts video_131.ts video_16.ts video_188.ts video_215.ts video_243.ts video_271.ts video_54.ts video_82.ts video_104.ts video_132.ts video_160.ts video_189.ts video_216.ts video_244.ts video_272.ts video_55.ts video_83.ts video_105.ts video_133.ts video_161.ts video_19.ts video_217.ts video_245.ts video_28.ts video_56.ts video_84.ts video_106.ts video_134.ts video_162.ts video_190.ts video_218.ts video_246.ts video_29.ts video_57.ts video_85.ts video_107.ts video_135.ts video_163.ts video_191.ts video_219.ts video_247.ts video_3.ts video_58.ts video_86.ts video_108.ts video_136.ts video_164.ts video_192.ts video_22.ts video_248.ts video_30.ts video_59.ts video_87.ts video_109.ts video_137.ts video_165.ts video_193.ts video_220.ts video_249.ts video_31.ts video_6.ts video_88.ts video_11.ts video_138.ts video_166.ts video_194.ts video_221.ts video_25.ts video_32.ts video_60.ts video_89.ts video_110.ts video_139.ts video_167.ts video_195.ts video_222.ts video_250.ts video_33.ts video_61.ts video_9.ts video_111.ts video_14.ts video_168.ts video_196.ts video_223.ts video_251.ts video_34.ts video_62.ts video_90.ts video_112.ts video_140.ts video_169.ts video_197.ts video_224.ts video_252.ts video_35.ts video_63.ts video_91.ts video_113.ts video_141.ts video_17.ts video_198.ts video_225.ts video_253.ts video_36.ts video_64.ts video_92.ts video_114.ts video_142.ts video_170.ts video_199.ts video_226.ts video_254.ts video_37.ts video_65.ts video_93.ts video_115.ts video_143.ts video_171.ts video_2.ts video_227.ts video_255.ts video_38.ts video_66.ts video_94.ts video_116.ts video_144.ts video_172.ts video_20.ts video_228.ts video_256.ts video_39.ts video_67.ts video_95.ts video_117.ts video_145.ts video_173.ts video_200.ts video_229.ts video_257.ts video_4.ts video_68.ts video_96.ts video_118.ts video_146.ts video_174.ts video_201.ts video_23.ts video_258.ts video_40.ts video_69.ts video_97.ts video_119.ts video_147.ts video_175.ts video_202.ts video_230.ts video_259.ts video_41.ts video_7.ts video_98.ts video_12.ts video_148.ts video_176.ts video_203.ts video_231.ts video_26.ts video_42.ts video_70.ts video_99.ts s video_120.ts video_149.ts video_177.ts video_204.ts video_232.ts video_260.ts video_43.ts video_71.ts video_121.ts video_15.ts video_178.ts video_205.ts video_233.ts video_261.ts video_44.ts video_72.ts video_122.ts video_150.ts video_179.ts video_206.ts video_234.ts video_262.ts video_45.ts video_73.ts video_123.ts video_151.ts video_18.ts video_207.ts video_235.ts video_263.ts video_46.ts video_74.tsCopy the code

It would be nice if we could combine these TS files into a video file.

TS file to synthesize an MP4 video. Note the following:

  • Some M3U8 videos are encrypted and the TS source file needs to be decrypted to play
  • The result is still a TS video, but it’s a little bigger, instead of changing the suffix to.MP4 which is just an MP4 video.

Encrypted video

The ext-x-key in M3U8 contains the encryption mode and KEY of M3U8. For example, video.yjf138.com: 8091/20180812/6 y… In # EXT – X – KEY: METHOD = AES – 128, URI = “KEY. The KEY” can be seen that encryption is symmetric encryption AES – 128, the KEY is the KEY. The KEY into the link is: video.yjf138.com: 8091/20180812/6 y… Then we can use AES-128 to decrypt. The usual way to do this is:

/** * @param sSrc @param sKey @return @param sKey */ private static byte[] decrypt(byte[] sSrc, String sKey, String method) { try { if (StringUtils.isNotEmpty(method) && ! Method. Contains ("AES")) {throw new M3u8Exception(" unknown algorithm! ") ); If (stringutils.isempty (sKey)) {return sSrc; } if (skey.length ()! = 16) {system.out. print("Key length is not 16 bits "); return null; } Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding"); SecretKeySpec keySpec = new SecretKeySpec(sKey.getBytes("utf-8"), "AES"); // If m3U8 has an IV label, AlgorithmParameterSpec paramSpec = new IvParameterSpec(new byte[16]); cipher.init(Cipher.DECRYPT_MODE, keySpec, paramSpec); return cipher.doFinal(sSrc); } catch (Exception ex) { ex.printStackTrace(); return null; }}Copy the code

But on the Android platform, this writing method is not compatible with all scenarios, because the crypto writing method on different Android levels is different, and the results obtained by calling the SYSTEM API will be different, so it is best to put the decrypting scene in the native layer, and use openSSL library to help us achieve decrypting.

TS converts to MP4

As mentioned earlier, the usual practice of TS merging is to read one TS fragment by one using an InputStream and then write it to a local MP4 file using an OutputStream. This looks like creating a new MP4 file, but is the new video actually in MP4 format?

Obviously not, because the package format for MP4 is completely different from TS. The best thing to do is to rewrite the resulting file according to the MP4 encapsulation rules, so that the resulting file must be an MP4 file.

We do not have to compare the bit flag of MP4 to generate one by one, as long as ffMPEG to help us achieve this transformation can be.

  • Decapsulate the source file and take out the audio and video streams of the source file
  • Creates the encapsulation header information for the object file.
  • Read the packet data and frame data from the source file audio stream and video stream, and then encapsulate them into the object file format according to the rules.

The final code can be found in the project: github.com/JeffMony/Vi…