9513506d4dcd5889d4e6acea0932a8fc6bb76d5b
[x262.git] / output / mp4_lsmash.c
1 /*****************************************************************************
2  * mp4_lsmash.c: mp4 muxer using L-SMASH
3  *****************************************************************************
4  * Copyright (C) 2003-2013 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
30 #include "output.h"
31 #include <lsmash.h>
32
33 #define H264_NALU_LENGTH_SIZE 4
34
35 /*******************/
36
37 #define MP4_LOG_ERROR( ... )                x264_cli_log( "mp4", X264_LOG_ERROR, __VA_ARGS__ )
38 #define MP4_LOG_WARNING( ... )              x264_cli_log( "mp4", X264_LOG_WARNING, __VA_ARGS__ )
39 #define MP4_LOG_INFO( ... )                 x264_cli_log( "mp4", X264_LOG_INFO, __VA_ARGS__ )
40 #define MP4_FAIL_IF_ERR( cond, ... )        FAIL_IF_ERR( cond, "mp4", __VA_ARGS__ )
41
42 /* For close_file() */
43 #define MP4_LOG_IF_ERR( cond, ... )\
44 if( cond )\
45 {\
46     MP4_LOG_ERROR( __VA_ARGS__ );\
47 }
48
49 /* For open_file() */
50 #define MP4_FAIL_IF_ERR_EX( cond, ... )\
51 if( cond )\
52 {\
53     remove_mp4_hnd( p_mp4 );\
54     MP4_LOG_ERROR( __VA_ARGS__ );\
55     return -1;\
56 }
57
58 /*******************/
59
60 typedef struct
61 {
62     lsmash_root_t *p_root;
63     lsmash_video_summary_t *summary;
64     int b_stdout;
65     uint32_t i_movie_timescale;
66     uint32_t i_video_timescale;
67     uint32_t i_track;
68     uint32_t i_sample_entry;
69     uint64_t i_time_inc;
70     int64_t i_start_offset;
71     uint64_t i_first_cts;
72     uint64_t i_prev_dts;
73     uint32_t i_sei_size;
74     uint8_t *p_sei_buffer;
75     int i_numframe;
76     int64_t i_init_delta;
77     int i_delay_frames;
78     int b_dts_compress;
79     int i_dts_compress_multiplier;
80     int b_use_recovery;
81     int b_fragments;
82 } mp4_hnd_t;
83
84 /*******************/
85
86 static void remove_mp4_hnd( hnd_t handle )
87 {
88     mp4_hnd_t *p_mp4 = handle;
89     if( !p_mp4 )
90         return;
91     if( p_mp4->p_sei_buffer )
92     {
93         free( p_mp4->p_sei_buffer );
94         p_mp4->p_sei_buffer = NULL;
95     }
96     if( p_mp4->p_root )
97     {
98         lsmash_destroy_root( p_mp4->p_root );
99         p_mp4->p_root = NULL;
100     }
101     free( p_mp4 );
102 }
103
104 /*******************/
105
106 static int close_file( hnd_t handle, int64_t largest_pts, int64_t second_largest_pts )
107 {
108     mp4_hnd_t *p_mp4 = handle;
109
110     if( !p_mp4 )
111         return 0;
112
113     if( p_mp4->p_root )
114     {
115         double actual_duration = 0;
116         if( p_mp4->i_track )
117         {
118             /* Flush the rest of samples and add the last sample_delta. */
119             uint32_t last_delta = largest_pts - second_largest_pts;
120             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 ),
121                             "failed to flush the rest of samples.\n" );
122
123             if( p_mp4->i_movie_timescale != 0 && p_mp4->i_video_timescale != 0 )    /* avoid zero division */
124                 actual_duration = ((double)((largest_pts + last_delta) * p_mp4->i_time_inc) / p_mp4->i_video_timescale) * p_mp4->i_movie_timescale;
125             else
126                 MP4_LOG_ERROR( "timescale is broken.\n" );
127
128             /*
129              * Declare the explicit time-line mapping.
130              * A segment_duration is given by movie timescale, while a media_time that is the start time of this segment
131              * is given by not the movie timescale but rather the media timescale.
132              * The reason is that ISO media have two time-lines, presentation and media time-line,
133              * and an edit maps the presentation time-line to the media time-line.
134              * According to QuickTime file format specification and the actual playback in QuickTime Player,
135              * if the Edit Box doesn't exist in the track, the ratio of the summation of sample durations and track's duration becomes
136              * the track's media_rate so that the entire media can be used by the track.
137              * So, we add Edit Box here to avoid this implicit media_rate could distort track's presentation timestamps slightly.
138              * Note: Any demuxers should follow the Edit List Box if it exists.
139              */
140             lsmash_edit_t edit;
141             edit.duration   = actual_duration;
142             edit.start_time = p_mp4->i_first_cts;
143             edit.rate       = ISOM_EDIT_MODE_NORMAL;
144             if( !p_mp4->b_fragments )
145             {
146                 MP4_LOG_IF_ERR( lsmash_create_explicit_timeline_map( p_mp4->p_root, p_mp4->i_track, edit ),
147                                 "failed to set timeline map for video.\n" );
148             }
149             else if( !p_mp4->b_stdout )
150                 MP4_LOG_IF_ERR( lsmash_modify_explicit_timeline_map( p_mp4->p_root, p_mp4->i_track, 1, edit ),
151                                 "failed to update timeline map for video.\n" );
152         }
153
154         MP4_LOG_IF_ERR( lsmash_finish_movie( p_mp4->p_root, NULL ), "failed to finish movie.\n" );
155     }
156
157     remove_mp4_hnd( p_mp4 ); /* including lsmash_destroy_root( p_mp4->p_root ); */
158
159     return 0;
160 }
161
162 static int open_file( char *psz_filename, hnd_t *p_handle, cli_output_opt_t *opt )
163 {
164     *p_handle = NULL;
165
166     int b_regular = strcmp( psz_filename, "-" );
167     b_regular = b_regular && x264_is_regular_file_path( psz_filename );
168     if( b_regular )
169     {
170         FILE *fh = x264_fopen( psz_filename, "wb" );
171         MP4_FAIL_IF_ERR( !fh, "cannot open output file `%s'.\n", psz_filename );
172         b_regular = x264_is_regular_file( fh );
173         fclose( fh );
174     }
175
176     mp4_hnd_t *p_mp4 = calloc( 1, sizeof(mp4_hnd_t) );
177     MP4_FAIL_IF_ERR( !p_mp4, "failed to allocate memory for muxer information.\n" );
178
179     p_mp4->b_dts_compress = opt->use_dts_compress;
180     p_mp4->b_use_recovery = 0; // we don't really support recovery
181     p_mp4->b_fragments    = !b_regular;
182     p_mp4->b_stdout       = !strcmp( psz_filename, "-" );
183
184     p_mp4->p_root = lsmash_open_movie( psz_filename, p_mp4->b_fragments ? LSMASH_FILE_MODE_WRITE_FRAGMENTED : LSMASH_FILE_MODE_WRITE );
185     MP4_FAIL_IF_ERR_EX( !p_mp4->p_root, "failed to create root.\n" );
186
187     p_mp4->summary = (lsmash_video_summary_t *)lsmash_create_summary( LSMASH_SUMMARY_TYPE_VIDEO );
188     MP4_FAIL_IF_ERR_EX( !p_mp4->summary,
189                         "failed to allocate memory for summary information of video.\n" );
190     p_mp4->summary->sample_type = ISOM_CODEC_TYPE_AVC1_VIDEO;
191
192     *p_handle = p_mp4;
193
194     return 0;
195 }
196
197 static int set_param( hnd_t handle, x264_param_t *p_param )
198 {
199     mp4_hnd_t *p_mp4 = handle;
200     uint64_t i_media_timescale;
201
202     p_mp4->i_delay_frames = p_param->i_bframe ? (p_param->i_bframe_pyramid ? 2 : 1) : 0;
203     p_mp4->i_dts_compress_multiplier = p_mp4->b_dts_compress * p_mp4->i_delay_frames + 1;
204
205     i_media_timescale = (uint64_t)p_param->i_timebase_den * p_mp4->i_dts_compress_multiplier;
206     p_mp4->i_time_inc = (uint64_t)p_param->i_timebase_num * p_mp4->i_dts_compress_multiplier;
207     MP4_FAIL_IF_ERR( i_media_timescale > UINT32_MAX, "MP4 media timescale %"PRIu64" exceeds maximum\n", i_media_timescale );
208
209     /* Select brands. */
210     lsmash_brand_type brands[6] = { 0 };
211     uint32_t brand_count = 0;
212     brands[brand_count++] = ISOM_BRAND_TYPE_MP42;
213     brands[brand_count++] = ISOM_BRAND_TYPE_MP41;
214     brands[brand_count++] = ISOM_BRAND_TYPE_ISOM;
215     if( p_mp4->b_use_recovery )
216     {
217         brands[brand_count++] = ISOM_BRAND_TYPE_AVC1;   /* sdtp, sgpd, sbgp and visual roll recovery grouping */
218         if( p_param->b_open_gop )
219             brands[brand_count++] = ISOM_BRAND_TYPE_ISO6;   /* cslg and visual random access grouping */
220     }
221
222     /* Set movie parameters. */
223     lsmash_movie_parameters_t movie_param;
224     lsmash_initialize_movie_parameters( &movie_param );
225     movie_param.major_brand = ISOM_BRAND_TYPE_MP42;
226     movie_param.brands = brands;
227     movie_param.number_of_brands = brand_count;
228     MP4_FAIL_IF_ERR( lsmash_set_movie_parameters( p_mp4->p_root, &movie_param ),
229                      "failed to set movie parameters.\n" );
230     p_mp4->i_movie_timescale = lsmash_get_movie_timescale( p_mp4->p_root );
231     MP4_FAIL_IF_ERR( !p_mp4->i_movie_timescale, "movie timescale is broken.\n" );
232
233     /* Create a video track. */
234     p_mp4->i_track = lsmash_create_track( p_mp4->p_root, ISOM_MEDIA_HANDLER_TYPE_VIDEO_TRACK );
235     MP4_FAIL_IF_ERR( !p_mp4->i_track, "failed to create a video track.\n" );
236
237     p_mp4->summary->width = p_param->i_width;
238     p_mp4->summary->height = p_param->i_height;
239     uint32_t i_display_width = p_param->i_width << 16;
240     uint32_t i_display_height = p_param->i_height << 16;
241     if( p_param->vui.i_sar_width && p_param->vui.i_sar_height )
242     {
243         double sar = (double)p_param->vui.i_sar_width / p_param->vui.i_sar_height;
244         if( sar > 1.0 )
245             i_display_width *= sar;
246         else
247             i_display_height /= sar;
248         p_mp4->summary->par_h = p_param->vui.i_sar_width;
249         p_mp4->summary->par_v = p_param->vui.i_sar_height;
250     }
251     p_mp4->summary->color.primaries_index = p_param->vui.i_colorprim;
252     p_mp4->summary->color.transfer_index  = p_param->vui.i_transfer;
253     p_mp4->summary->color.matrix_index    = p_param->vui.i_colmatrix >= 0 ? p_param->vui.i_colmatrix : ISOM_MATRIX_INDEX_UNSPECIFIED;
254     p_mp4->summary->color.full_range      = p_param->vui.b_fullrange >= 0 ? p_param->vui.b_fullrange : 0;
255
256     /* Set video track parameters. */
257     lsmash_track_parameters_t track_param;
258     lsmash_initialize_track_parameters( &track_param );
259     lsmash_track_mode track_mode = ISOM_TRACK_ENABLED | ISOM_TRACK_IN_MOVIE | ISOM_TRACK_IN_PREVIEW;
260     track_param.mode = track_mode;
261     track_param.display_width = i_display_width;
262     track_param.display_height = i_display_height;
263     MP4_FAIL_IF_ERR( lsmash_set_track_parameters( p_mp4->p_root, p_mp4->i_track, &track_param ),
264                      "failed to set track parameters for video.\n" );
265
266     /* Set video media parameters. */
267     lsmash_media_parameters_t media_param;
268     lsmash_initialize_media_parameters( &media_param );
269     media_param.timescale = i_media_timescale;
270     media_param.media_handler_name = "L-SMASH Video Media Handler";
271     if( p_mp4->b_use_recovery )
272     {
273         media_param.roll_grouping = p_param->b_intra_refresh;
274         media_param.rap_grouping = p_param->b_open_gop;
275     }
276     MP4_FAIL_IF_ERR( lsmash_set_media_parameters( p_mp4->p_root, p_mp4->i_track, &media_param ),
277                      "failed to set media parameters for video.\n" );
278     p_mp4->i_video_timescale = lsmash_get_media_timescale( p_mp4->p_root, p_mp4->i_track );
279     MP4_FAIL_IF_ERR( !p_mp4->i_video_timescale, "media timescale for video is broken.\n" );
280
281     return 0;
282 }
283
284 static int write_headers( hnd_t handle, x264_nal_t *p_nal )
285 {
286     mp4_hnd_t *p_mp4 = handle;
287
288     uint32_t sps_size = p_nal[0].i_payload - H264_NALU_LENGTH_SIZE;
289     uint32_t pps_size = p_nal[1].i_payload - H264_NALU_LENGTH_SIZE;
290     uint32_t sei_size = p_nal[2].i_payload;
291
292     uint8_t *sps = p_nal[0].p_payload + H264_NALU_LENGTH_SIZE;
293     uint8_t *pps = p_nal[1].p_payload + H264_NALU_LENGTH_SIZE;
294     uint8_t *sei = p_nal[2].p_payload;
295
296     lsmash_codec_specific_t *cs = lsmash_create_codec_specific_data( LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_VIDEO_H264,
297                                                                      LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED );
298
299     lsmash_h264_specific_parameters_t *param = (lsmash_h264_specific_parameters_t *)cs->data.structured;
300     param->lengthSizeMinusOne = H264_NALU_LENGTH_SIZE - 1;
301
302     /* SPS
303      * The remaining parameters are automatically set by SPS. */
304     if( lsmash_append_h264_parameter_set( param, H264_PARAMETER_SET_TYPE_SPS, sps, sps_size ) )
305     {
306         MP4_LOG_ERROR( "failed to append SPS.\n" );
307         return -1;
308     }
309
310     /* PPS */
311     if( lsmash_append_h264_parameter_set( param, H264_PARAMETER_SET_TYPE_PPS, pps, pps_size ) )
312     {
313         MP4_LOG_ERROR( "failed to append PPS.\n" );
314         return -1;
315     }
316
317     if( lsmash_add_codec_specific_data( (lsmash_summary_t *)p_mp4->summary, cs ) )
318     {
319         MP4_LOG_ERROR( "failed to add H.264 specific info.\n" );
320         return -1;
321     }
322
323     lsmash_destroy_codec_specific_data( cs );
324
325     /* Additional extensions */
326     /* Bitrate info */
327     cs = lsmash_create_codec_specific_data( LSMASH_CODEC_SPECIFIC_DATA_TYPE_ISOM_VIDEO_H264_BITRATE,
328                                             LSMASH_CODEC_SPECIFIC_FORMAT_STRUCTURED );
329     if( cs )
330         lsmash_add_codec_specific_data( (lsmash_summary_t *)p_mp4->summary, cs );
331     lsmash_destroy_codec_specific_data( cs );
332
333     p_mp4->i_sample_entry = lsmash_add_sample_entry( p_mp4->p_root, p_mp4->i_track, p_mp4->summary );
334     MP4_FAIL_IF_ERR( !p_mp4->i_sample_entry,
335                      "failed to add sample entry for video.\n" );
336
337     /* SEI */
338     p_mp4->p_sei_buffer = malloc( sei_size );
339     MP4_FAIL_IF_ERR( !p_mp4->p_sei_buffer,
340                      "failed to allocate sei transition buffer.\n" );
341     memcpy( p_mp4->p_sei_buffer, sei, sei_size );
342     p_mp4->i_sei_size = sei_size;
343
344     return sei_size + sps_size + pps_size;
345 }
346
347 static int write_frame( hnd_t handle, uint8_t *p_nalu, int i_size, x264_picture_t *p_picture )
348 {
349     mp4_hnd_t *p_mp4 = handle;
350     uint64_t dts, cts;
351
352     if( !p_mp4->i_numframe )
353     {
354         p_mp4->i_start_offset = p_picture->i_dts * -1;
355         p_mp4->i_first_cts = p_mp4->b_dts_compress ? 0 : p_mp4->i_start_offset * p_mp4->i_time_inc;
356         if( p_mp4->b_fragments )
357         {
358             lsmash_edit_t edit;
359             edit.duration   = ISOM_EDIT_DURATION_UNKNOWN32;     /* QuickTime doesn't support 64bit duration. */
360             edit.start_time = p_mp4->i_first_cts;
361             edit.rate       = ISOM_EDIT_MODE_NORMAL;
362             MP4_LOG_IF_ERR( lsmash_create_explicit_timeline_map( p_mp4->p_root, p_mp4->i_track, edit ),
363                             "failed to set timeline map for video.\n" );
364         }
365     }
366
367     lsmash_sample_t *p_sample = lsmash_create_sample( i_size + p_mp4->i_sei_size );
368     MP4_FAIL_IF_ERR( !p_sample,
369                      "failed to create a video sample data.\n" );
370
371     if( p_mp4->p_sei_buffer )
372     {
373         memcpy( p_sample->data, p_mp4->p_sei_buffer, p_mp4->i_sei_size );
374         free( p_mp4->p_sei_buffer );
375         p_mp4->p_sei_buffer = NULL;
376     }
377
378     memcpy( p_sample->data + p_mp4->i_sei_size, p_nalu, i_size );
379     p_mp4->i_sei_size = 0;
380
381     if( p_mp4->b_dts_compress )
382     {
383         if( p_mp4->i_numframe == 1 )
384             p_mp4->i_init_delta = (p_picture->i_dts + p_mp4->i_start_offset) * p_mp4->i_time_inc;
385         dts = p_mp4->i_numframe > p_mp4->i_delay_frames
386             ? p_picture->i_dts * p_mp4->i_time_inc
387             : p_mp4->i_numframe * (p_mp4->i_init_delta / p_mp4->i_dts_compress_multiplier);
388         cts = p_picture->i_pts * p_mp4->i_time_inc;
389     }
390     else
391     {
392         dts = (p_picture->i_dts + p_mp4->i_start_offset) * p_mp4->i_time_inc;
393         cts = (p_picture->i_pts + p_mp4->i_start_offset) * p_mp4->i_time_inc;
394     }
395
396     p_sample->dts = dts;
397     p_sample->cts = cts;
398     p_sample->index = p_mp4->i_sample_entry;
399     p_sample->prop.ra_flags = p_picture->b_keyframe ? ISOM_SAMPLE_RANDOM_ACCESS_FLAG_SYNC : ISOM_SAMPLE_RANDOM_ACCESS_FLAG_NONE;
400
401     if( p_mp4->b_fragments && p_mp4->i_numframe && p_sample->prop.ra_flags != ISOM_SAMPLE_RANDOM_ACCESS_FLAG_NONE )
402     {
403         MP4_FAIL_IF_ERR( lsmash_flush_pooled_samples( p_mp4->p_root, p_mp4->i_track, p_sample->dts - p_mp4->i_prev_dts ),
404                          "failed to flush the rest of samples.\n" );
405         MP4_FAIL_IF_ERR( lsmash_create_fragment_movie( p_mp4->p_root ),
406                          "failed to create a movie fragment.\n" );
407     }
408
409     /* Append data per sample. */
410     MP4_FAIL_IF_ERR( lsmash_append_sample( p_mp4->p_root, p_mp4->i_track, p_sample ),
411                      "failed to append a video frame.\n" );
412
413     p_mp4->i_prev_dts = dts;
414     p_mp4->i_numframe++;
415
416     return i_size;
417 }
418
419 const cli_output_t mp4_output = { open_file, set_param, write_headers, write_frame, close_file };