mp4_lsmash.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429
  1. /*****************************************************************************
  2. * mp4_lsmash.c: mp4 muxer using L-SMASH
  3. *****************************************************************************
  4. * Copyright (C) 2003-2018 x264 project
  5. *
  6. * Authors: Laurent Aimar <fenrir@via.ecp.fr>
  7. * Loren Merritt <lorenm@u.washington.edu>
  8. * Yusuke Nakamura <muken.the.vfrmaniac@gmail.com>
  9. * Takashi Hirata <silverfilain@gmail.com>
  10. * golgol7777 <golgol7777@gmail.com>
  11. *
  12. * This program is free software; you can redistribute it and/or modify
  13. * it under the terms of the GNU General Public License as published by
  14. * the Free Software Foundation; either version 2 of the License, or
  15. * (at your option) any later version.
  16. *
  17. * This program is distributed in the hope that it will be useful,
  18. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  19. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  20. * GNU General Public License for more details.
  21. *
  22. * You should have received a copy of the GNU General Public License
  23. * along with this program; if not, write to the Free Software
  24. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA.
  25. *
  26. * This program is also available under a commercial proprietary license.
  27. * For more information, contact us at licensing@x264.com.
  28. *****************************************************************************/
  29. #include "output.h"
  30. #include <lsmash.h>
  31. #define H264_NALU_LENGTH_SIZE 4
  32. /*******************/
  33. #define MP4_LOG_ERROR( ... ) x264_cli_log( "mp4", X264_LOG_ERROR, __VA_ARGS__ )
  34. #define MP4_LOG_WARNING( ... ) x264_cli_log( "mp4", X264_LOG_WARNING, __VA_ARGS__ )
  35. #define MP4_LOG_INFO( ... ) x264_cli_log( "mp4", X264_LOG_INFO, __VA_ARGS__ )
  36. #define MP4_FAIL_IF_ERR( cond, ... ) FAIL_IF_ERR( cond, "mp4", __VA_ARGS__ )
  37. /* For close_file() */
  38. #define MP4_LOG_IF_ERR( cond, ... )\
  39. do\
  40. {\
  41. if( cond )\
  42. {\
  43. MP4_LOG_ERROR( __VA_ARGS__ );\
  44. }\
  45. } while( 0 )
  46. /* For open_file() */
  47. #define MP4_FAIL_IF_ERR_EX( cond, ... )\
  48. do\
  49. {\
  50. if( cond )\
  51. {\
  52. remove_mp4_hnd( p_mp4 );\
  53. MP4_LOG_ERROR( __VA_ARGS__ );\
  54. return -1;\
  55. }\
  56. } while( 0 )
  57. /*******************/
  58. typedef struct
  59. {
  60. lsmash_root_t *p_root;
  61. lsmash_video_summary_t *summary;
  62. int b_stdout;
  63. uint32_t i_movie_timescale;
  64. uint32_t i_video_timescale;
  65. uint32_t i_track;
  66. uint32_t i_sample_entry;
  67. uint64_t i_time_inc;
  68. int64_t i_start_offset;
  69. uint64_t i_first_cts;
  70. uint64_t i_prev_dts;
  71. uint32_t i_sei_size;
  72. uint8_t *p_sei_buffer;
  73. int i_numframe;
  74. int64_t i_init_delta;
  75. int i_delay_frames;
  76. int b_dts_compress;
  77. int i_dts_compress_multiplier;
  78. int b_use_recovery;
  79. int b_fragments;
  80. lsmash_file_parameters_t file_param;
  81. } mp4_hnd_t;
  82. /*******************/
  83. static void remove_mp4_hnd( hnd_t handle )
  84. {
  85. mp4_hnd_t *p_mp4 = handle;
  86. if( !p_mp4 )
  87. return;
  88. lsmash_cleanup_summary( (lsmash_summary_t *)p_mp4->summary );
  89. lsmash_close_file( &p_mp4->file_param );
  90. lsmash_destroy_root( p_mp4->p_root );
  91. free( p_mp4->p_sei_buffer );
  92. free( p_mp4 );
  93. }
  94. /*******************/
  95. static int close_file( hnd_t handle, int64_t largest_pts, int64_t second_largest_pts )
  96. {
  97. mp4_hnd_t *p_mp4 = handle;
  98. if( !p_mp4 )
  99. return 0;
  100. if( p_mp4->p_root )
  101. {
  102. double actual_duration = 0;
  103. if( p_mp4->i_track )
  104. {
  105. /* Flush the rest of samples and add the last sample_delta. */
  106. uint32_t last_delta = largest_pts - second_largest_pts;
  107. MP4_LOG_IF_ERR( lsmash_flush_pooled_samples( p_mp4->p_root, p_mp4->i_track, (last_delta ? last_delta : 1) * p_mp4->i_time_inc ),
  108. "failed to flush the rest of samples.\n" );
  109. if( p_mp4->i_movie_timescale != 0 && p_mp4->i_video_timescale != 0 ) /* avoid zero division */
  110. actual_duration = ((double)((largest_pts + last_delta) * p_mp4->i_time_inc) / p_mp4->i_video_timescale) * p_mp4->i_movie_timescale;
  111. else
  112. MP4_LOG_ERROR( "timescale is broken.\n" );
  113. /*
  114. * Declare the explicit time-line mapping.
  115. * A segment_duration is given by movie timescale, while a media_time that is the start time of this segment
  116. * is given by not the movie timescale but rather the media timescale.
  117. * The reason is that ISO media have two time-lines, presentation and media time-line,
  118. * and an edit maps the presentation time-line to the media time-line.
  119. * According to QuickTime file format specification and the actual playback in QuickTime Player,
  120. * if the Edit Box doesn't exist in the track, the ratio of the summation of sample durations and track's duration becomes
  121. * the track's media_rate so that the entire media can be used by the track.
  122. * So, we add Edit Box here to avoid this implicit media_rate could distort track's presentation timestamps slightly.
  123. * Note: Any demuxers should follow the Edit List Box if it exists.
  124. */
  125. lsmash_edit_t edit;
  126. edit.duration = actual_duration;
  127. edit.start_time = p_mp4->i_first_cts;
  128. edit.rate = ISOM_EDIT_MODE_NORMAL;
  129. if( !p_mp4->b_fragments )
  130. {
  131. MP4_LOG_IF_ERR( lsmash_create_explicit_timeline_map( p_mp4->p_root, p_mp4->i_track, edit ),
  132. "failed to set timeline map for video.\n" );
  133. }
  134. else if( !p_mp4->b_stdout )
  135. MP4_LOG_IF_ERR( lsmash_modify_explicit_timeline_map( p_mp4->p_root, p_mp4->i_track, 1, edit ),
  136. "failed to update timeline map for video.\n" );
  137. }
  138. MP4_LOG_IF_ERR( lsmash_finish_movie( p_mp4->p_root, NULL ), "failed to finish movie.\n" );
  139. }
  140. remove_mp4_hnd( p_mp4 ); /* including lsmash_destroy_root( p_mp4->p_root ); */
  141. return 0;
  142. }
  143. static int open_file( char *psz_filename, hnd_t *p_handle, cli_output_opt_t *opt )
  144. {
  145. *p_handle = NULL;
  146. int b_regular = strcmp( psz_filename, "-" );
  147. b_regular = b_regular && x264_is_regular_file_path( psz_filename );
  148. if( b_regular )
  149. {
  150. FILE *fh = x264_fopen( psz_filename, "wb" );
  151. MP4_FAIL_IF_ERR( !fh, "cannot open output file `%s'.\n", psz_filename );
  152. b_regular = x264_is_regular_file( fh );
  153. fclose( fh );
  154. }
  155. mp4_hnd_t *p_mp4 = calloc( 1, sizeof(mp4_hnd_t) );
  156. MP4_FAIL_IF_ERR( !p_mp4, "failed to allocate memory for muxer information.\n" );
  157. p_mp4->b_dts_compress = opt->use_dts_compress;
  158. p_mp4->b_use_recovery = 0; // we don't really support recovery
  159. p_mp4->b_fragments = !b_regular;
  160. p_mp4->b_stdout = !strcmp( psz_filename, "-" );
  161. p_mp4->p_root = lsmash_create_root();
  162. MP4_FAIL_IF_ERR_EX( !p_mp4->p_root, "failed to create root.\n" );
  163. MP4_FAIL_IF_ERR_EX( lsmash_open_file( psz_filename, 0, &p_mp4->file_param ) < 0, "failed to open an output file.\n" );
  164. if( p_mp4->b_fragments )
  165. p_mp4->file_param.mode |= LSMASH_FILE_MODE_FRAGMENTED;
  166. p_mp4->summary = (lsmash_video_summary_t *)lsmash_create_summary( LSMASH_SUMMARY_TYPE_VIDEO );
  167. MP4_FAIL_IF_ERR_EX( !p_mp4->summary,
  168. "failed to allocate memory for summary information of video.\n" );
  169. p_mp4->summary->sample_type = ISOM_CODEC_TYPE_AVC1_VIDEO;
  170. *p_handle = p_mp4;
  171. return 0;
  172. }
  173. static int set_param( hnd_t handle, x264_param_t *p_param )
  174. {
  175. mp4_hnd_t *p_mp4 = handle;
  176. uint64_t i_media_timescale;
  177. p_mp4->i_delay_frames = p_param->i_bframe ? (p_param->i_bframe_pyramid ? 2 : 1) : 0;
  178. p_mp4->i_dts_compress_multiplier = p_mp4->b_dts_compress * p_mp4->i_delay_frames + 1;
  179. i_media_timescale = (uint64_t)p_param->i_timebase_den * p_mp4->i_dts_compress_multiplier;
  180. p_mp4->i_time_inc = (uint64_t)p_param->i_timebase_num * p_mp4->i_dts_compress_multiplier;
  181. MP4_FAIL_IF_ERR( i_media_timescale > UINT32_MAX, "MP4 media timescale %"PRIu64" exceeds maximum\n", i_media_timescale );
  182. /* Select brands. */
  183. lsmash_brand_type brands[6] = { 0 };
  184. uint32_t brand_count = 0;
  185. brands[brand_count++] = ISOM_BRAND_TYPE_MP42;
  186. brands[brand_count++] = ISOM_BRAND_TYPE_MP41;
  187. brands[brand_count++] = ISOM_BRAND_TYPE_ISOM;
  188. if( p_mp4->b_use_recovery )
  189. {
  190. brands[brand_count++] = ISOM_BRAND_TYPE_AVC1; /* sdtp, sgpd, sbgp and visual roll recovery grouping */
  191. if( p_param->b_open_gop )
  192. brands[brand_count++] = ISOM_BRAND_TYPE_ISO6; /* cslg and visual random access grouping */
  193. }
  194. /* Set file */
  195. lsmash_file_parameters_t *file_param = &p_mp4->file_param;
  196. file_param->major_brand = brands[0];
  197. file_param->brands = brands;
  198. file_param->brand_count = brand_count;
  199. file_param->minor_version = 0;
  200. MP4_FAIL_IF_ERR( !lsmash_set_file( p_mp4->p_root, file_param ), "failed to add an output file into a ROOT.\n" );
  201. /* Set movie parameters. */
  202. lsmash_movie_parameters_t movie_param;
  203. lsmash_initialize_movie_parameters( &movie_param );
  204. MP4_FAIL_IF_ERR( lsmash_set_movie_parameters( p_mp4->p_root, &movie_param ),
  205. "failed to set movie parameters.\n" );
  206. p_mp4->i_movie_timescale = lsmash_get_movie_timescale( p_mp4->p_root );
  207. MP4_FAIL_IF_ERR( !p_mp4->i_movie_timescale, "movie timescale is broken.\n" );
  208. /* Create a video track. */
  209. p_mp4->i_track = lsmash_create_track( p_mp4->p_root, ISOM_MEDIA_HANDLER_TYPE_VIDEO_TRACK );
  210. MP4_FAIL_IF_ERR( !p_mp4->i_track, "failed to create a video track.\n" );
  211. p_mp4->summary->width = p_param->i_width;
  212. p_mp4->summary->height = p_param->i_height;
  213. uint32_t i_display_width = p_param->i_width << 16;
  214. uint32_t i_display_height = p_param->i_height << 16;
  215. if( p_param->vui.i_sar_width && p_param->vui.i_sar_height )
  216. {
  217. double sar = (double)p_param->vui.i_sar_width / p_param->vui.i_sar_height;
  218. if( sar > 1.0 )
  219. i_display_width *= sar;
  220. else
  221. i_display_height /= sar;
  222. p_mp4->summary->par_h = p_param->vui.i_sar_width;
  223. p_mp4->summary->par_v = p_param->vui.i_sar_height;
  224. }
  225. p_mp4->summary->color.primaries_index = p_param->vui.i_colorprim;
  226. p_mp4->summary->color.transfer_index = p_param->vui.i_transfer;
  227. p_mp4->summary->color.matrix_index = p_param->vui.i_colmatrix >= 0 ? p_param->vui.i_colmatrix : ISOM_MATRIX_INDEX_UNSPECIFIED;
  228. p_mp4->summary->color.full_range = p_param->vui.b_fullrange >= 0 ? p_param->vui.b_fullrange : 0;
  229. /* Set video track parameters. */
  230. lsmash_track_parameters_t track_param;
  231. lsmash_initialize_track_parameters( &track_param );
  232. lsmash_track_mode track_mode = ISOM_TRACK_ENABLED | ISOM_TRACK_IN_MOVIE | ISOM_TRACK_IN_PREVIEW;
  233. track_param.mode = track_mode;
  234. track_param.display_width = i_display_width;
  235. track_param.display_height = i_display_height;
  236. MP4_FAIL_IF_ERR( lsmash_set_track_parameters( p_mp4->p_root, p_mp4->i_track, &track_param ),
  237. "failed to set track parameters for video.\n" );
  238. /* Set video media parameters. */
  239. lsmash_media_parameters_t media_param;
  240. lsmash_initialize_media_parameters( &media_param );
  241. media_param.timescale = i_media_timescale;
  242. media_param.media_handler_name = "L-SMASH Video Media Handler";
  243. if( p_mp4->b_use_recovery )
  244. {
  245. media_param.roll_grouping = p_param->b_intra_refresh;
  246. media_param.rap_grouping = p_param->b_open_gop;
  247. }
  248. MP4_FAIL_IF_ERR( lsmash_set_media_parameters( p_mp4->p_root, p_mp4->i_track, &media_param ),
  249. "failed to set media parameters for video.\n" );
  250. p_mp4->i_video_timescale = lsmash_get_media_timescale( p_mp4->p_root, p_mp4->i_track );
  251. MP4_FAIL_IF_ERR( !p_mp4->i_video_timescale, "media timescale for video is broken.\n" );
  252. return 0;
  253. }
  254. static int write_headers( hnd_t handle, x264_nal_t *p_nal )
  255. {
  256. mp4_hnd_t *p_mp4 = handle;
  257. uint32_t sps_size = p_nal[0].i_payload - H264_NALU_LENGTH_SIZE;
  258. uint32_t pps_size = p_nal[1].i_payload - H264_NALU_LENGTH_SIZE;
  259. uint32_t sei_size = p_nal[2].i_payload;
  260. uint8_t *sps = p_nal[0].p_payload + H264_NALU_LENGTH_SIZE;
  261. uint8_t *pps = p_nal[1].p_payload + H264_NALU_LENGTH_SIZE;
  262. uint8_t *sei = p_nal[2].p_payload;
  263. lsmash_codec_specific_t *cs = lsmash_create_codec_specific_data( LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_VIDEO_H264,
  264. LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED );
  265. lsmash_h264_specific_parameters_t *param = (lsmash_h264_specific_parameters_t *)cs->data.structured;
  266. param->lengthSizeMinusOne = H264_NALU_LENGTH_SIZE - 1;
  267. /* SPS
  268. * The remaining parameters are automatically set by SPS. */
  269. if( lsmash_append_h264_parameter_set( param, H264_PARAMETER_SET_TYPE_SPS, sps, sps_size ) )
  270. {
  271. MP4_LOG_ERROR( "failed to append SPS.\n" );
  272. return -1;
  273. }
  274. /* PPS */
  275. if( lsmash_append_h264_parameter_set( param, H264_PARAMETER_SET_TYPE_PPS, pps, pps_size ) )
  276. {
  277. MP4_LOG_ERROR( "failed to append PPS.\n" );
  278. return -1;
  279. }
  280. if( lsmash_add_codec_specific_data( (lsmash_summary_t *)p_mp4->summary, cs ) )
  281. {
  282. MP4_LOG_ERROR( "failed to add H.264 specific info.\n" );
  283. return -1;
  284. }
  285. lsmash_destroy_codec_specific_data( cs );
  286. /* Additional extensions */
  287. /* Bitrate info */
  288. cs = lsmash_create_codec_specific_data( LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_VIDEO_H264_BITRATE,
  289. LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED );
  290. if( cs )
  291. lsmash_add_codec_specific_data( (lsmash_summary_t *)p_mp4->summary, cs );
  292. lsmash_destroy_codec_specific_data( cs );
  293. p_mp4->i_sample_entry = lsmash_add_sample_entry( p_mp4->p_root, p_mp4->i_track, p_mp4->summary );
  294. MP4_FAIL_IF_ERR( !p_mp4->i_sample_entry,
  295. "failed to add sample entry for video.\n" );
  296. /* SEI */
  297. p_mp4->p_sei_buffer = malloc( sei_size );
  298. MP4_FAIL_IF_ERR( !p_mp4->p_sei_buffer,
  299. "failed to allocate sei transition buffer.\n" );
  300. memcpy( p_mp4->p_sei_buffer, sei, sei_size );
  301. p_mp4->i_sei_size = sei_size;
  302. return sei_size + sps_size + pps_size;
  303. }
  304. static int write_frame( hnd_t handle, uint8_t *p_nalu, int i_size, x264_picture_t *p_picture )
  305. {
  306. mp4_hnd_t *p_mp4 = handle;
  307. uint64_t dts, cts;
  308. if( !p_mp4->i_numframe )
  309. {
  310. p_mp4->i_start_offset = p_picture->i_dts * -1;
  311. p_mp4->i_first_cts = p_mp4->b_dts_compress ? 0 : p_mp4->i_start_offset * p_mp4->i_time_inc;
  312. if( p_mp4->b_fragments )
  313. {
  314. lsmash_edit_t edit;
  315. edit.duration = ISOM_EDIT_DURATION_UNKNOWN32; /* QuickTime doesn't support 64bit duration. */
  316. edit.start_time = p_mp4->i_first_cts;
  317. edit.rate = ISOM_EDIT_MODE_NORMAL;
  318. MP4_LOG_IF_ERR( lsmash_create_explicit_timeline_map( p_mp4->p_root, p_mp4->i_track, edit ),
  319. "failed to set timeline map for video.\n" );
  320. }
  321. }
  322. lsmash_sample_t *p_sample = lsmash_create_sample( i_size + p_mp4->i_sei_size );
  323. MP4_FAIL_IF_ERR( !p_sample,
  324. "failed to create a video sample data.\n" );
  325. if( p_mp4->p_sei_buffer )
  326. {
  327. memcpy( p_sample->data, p_mp4->p_sei_buffer, p_mp4->i_sei_size );
  328. free( p_mp4->p_sei_buffer );
  329. p_mp4->p_sei_buffer = NULL;
  330. }
  331. memcpy( p_sample->data + p_mp4->i_sei_size, p_nalu, i_size );
  332. p_mp4->i_sei_size = 0;
  333. if( p_mp4->b_dts_compress )
  334. {
  335. if( p_mp4->i_numframe == 1 )
  336. p_mp4->i_init_delta = (p_picture->i_dts + p_mp4->i_start_offset) * p_mp4->i_time_inc;
  337. dts = p_mp4->i_numframe > p_mp4->i_delay_frames
  338. ? p_picture->i_dts * p_mp4->i_time_inc
  339. : p_mp4->i_numframe * (p_mp4->i_init_delta / p_mp4->i_dts_compress_multiplier);
  340. cts = p_picture->i_pts * p_mp4->i_time_inc;
  341. }
  342. else
  343. {
  344. dts = (p_picture->i_dts + p_mp4->i_start_offset) * p_mp4->i_time_inc;
  345. cts = (p_picture->i_pts + p_mp4->i_start_offset) * p_mp4->i_time_inc;
  346. }
  347. p_sample->dts = dts;
  348. p_sample->cts = cts;
  349. p_sample->index = p_mp4->i_sample_entry;
  350. p_sample->prop.ra_flags = p_picture->b_keyframe ? ISOM_SAMPLE_RANDOM_ACCESS_FLAG_SYNC : ISOM_SAMPLE_RANDOM_ACCESS_FLAG_NONE;
  351. if( p_mp4->b_fragments && p_mp4->i_numframe && p_sample->prop.ra_flags != ISOM_SAMPLE_RANDOM_ACCESS_FLAG_NONE )
  352. {
  353. MP4_FAIL_IF_ERR( lsmash_flush_pooled_samples( p_mp4->p_root, p_mp4->i_track, p_sample->dts - p_mp4->i_prev_dts ),
  354. "failed to flush the rest of samples.\n" );
  355. MP4_FAIL_IF_ERR( lsmash_create_fragment_movie( p_mp4->p_root ),
  356. "failed to create a movie fragment.\n" );
  357. }
  358. /* Append data per sample. */
  359. MP4_FAIL_IF_ERR( lsmash_append_sample( p_mp4->p_root, p_mp4->i_track, p_sample ),
  360. "failed to append a video frame.\n" );
  361. p_mp4->i_prev_dts = dts;
  362. p_mp4->i_numframe++;
  363. return i_size;
  364. }
  365. const cli_output_t mp4_output = { open_file, set_param, write_headers, write_frame, close_file };