@@ -29,60 +29,40 @@ typedef struct StreamingContext {
2929} StreamingContext ;
3030
3131int fill_stream_info (AVStream * avs , AVCodec * * avc , AVCodecContext * * avcc ) {
32- //https://www.ffmpeg.org/doxygen/trunk/group__lavc__decoding.html#ga19a0ca553277f019dd5b0fec6e1f9dca
33- // Find a registered decoder with a matching codec ID.
3432 * avc = avcodec_find_decoder (avs -> codecpar -> codec_id );
3533 if (!* avc ) {logging ("failed to find the codec" ); return -1 ;}
3634
37- //https://www.ffmpeg.org/doxygen/trunk/group__lavc__core.html#gae80afec6f26df6607eaacf39b561c315
38- // Allocate an AVCodecContext and set its fields to default values.
3935 * avcc = avcodec_alloc_context3 (* avc );
4036 if (!* avcc ) {logging ("failed to alloc memory for codec context" ); return -1 ;}
4137
42- //https://www.ffmpeg.org/doxygen/trunk/group__lavc__core.html#gac7b282f51540ca7a99416a3ba6ee0d16
43- // Fill the codec context based on the values from the supplied codec parameters.
4438 if (avcodec_parameters_to_context (* avcc , avs -> codecpar ) < 0 ) {logging ("failed to fill codec context" ); return -1 ;}
4539
46- //https://www.ffmpeg.org/doxygen/trunk/group__lavc__core.html#ga11f785a188d7d9df71621001465b0f1d
47- // Initialize the AVCodecContext to use the given AVCodec.
4840 if (avcodec_open2 (* avcc , * avc , NULL ) < 0 ) {logging ("failed to open codec" ); return -1 ;}
4941 return 0 ;
5042}
5143
5244int open_media (const char * in_filename , AVFormatContext * * avfc ) {
53- //https://www.ffmpeg.org/doxygen/trunk/group__lavf__core.html#gac7a91abf2f59648d995894711f070f62
54- // Allocate an AVFormatContext.
5545 * avfc = avformat_alloc_context ();
5646 if (!* avfc ) {logging ("failed to alloc memory for format" ); return -1 ;}
5747
58- //https://www.ffmpeg.org/doxygen/trunk/group__lavf__decoding.html#gaff468dcc45289542f4c30d311bc2a201
59- // Open an input stream and read the header.
6048 if (avformat_open_input (avfc , in_filename , NULL , NULL ) != 0 ) {logging ("failed to open input file %s" , in_filename ); return -1 ;}
6149
62- //https://www.ffmpeg.org/doxygen/trunk/group__lavf__decoding.html#gad42172e27cddafb81096939783b157bb
63- // Read packets of a media file to get stream information.
6450 if (avformat_find_stream_info (* avfc , NULL ) < 0 ) {logging ("failed to get stream info" ); return -1 ;}
6551 return 0 ;
6652}
6753
6854int prepare_decoder (StreamingContext * sc ) {
69- // iterating through all the input streams (audio, video, subtitles and etc)
70- // if we have multiples streams of audio and video we're going to take the last
7155 for (int i = 0 ; i < sc -> avfc -> nb_streams ; i ++ ) {
7256 if (sc -> avfc -> streams [i ]-> codecpar -> codec_type == AVMEDIA_TYPE_VIDEO ) {
73- // keeping a pointer to the video av stream
7457 sc -> video_avs = sc -> avfc -> streams [i ];
7558 sc -> video_index = i ;
7659
7760 if (fill_stream_info (sc -> video_avs , & sc -> video_avc , & sc -> video_avcc )) {return -1 ;}
78- //print_timing("Video timming info from the decoder preparation", sc->avfc, sc->video_avcc, sc->video_avs);
7961 } else if (sc -> avfc -> streams [i ]-> codecpar -> codec_type == AVMEDIA_TYPE_AUDIO ) {
80- // keeping a pointer to the audio av stream
8162 sc -> audio_avs = sc -> avfc -> streams [i ];
8263 sc -> audio_index = i ;
8364
8465 if (fill_stream_info (sc -> audio_avs , & sc -> audio_avc , & sc -> audio_avcc )) {return -1 ;}
85- //print_timing("Audio timming info from the decoder preparation", sc->avfc, sc->audio_avcc, sc->audio_avs);
8666 } else {
8767 logging ("skipping streams other than audio and video" );
8868 }
@@ -94,73 +74,37 @@ int prepare_decoder(StreamingContext *sc) {
9474int prepare_encoder (StreamingContext * sc , AVCodecContext * decoder_ctx , AVRational input_framerate ) {
9575 sc -> video_avs = avformat_new_stream (sc -> avfc , NULL );
9676
97- //https://www.ffmpeg.org/doxygen/trunk/group__lavc__encoding.html#gaa614ffc38511c104bdff4a3afa086d37
98- // Find a registered encoder with the specified name.
9977 sc -> video_avc = avcodec_find_encoder_by_name ("libx264" );
10078 if (!sc -> video_avc ) {logging ("could not find the proper codec" ); return -1 ;}
10179
102- //https://www.ffmpeg.org/doxygen/trunk/group__lavc__core.html#gae80afec6f26df6607eaacf39b561c315
103- // Allocate an AVCodecContext and set its fields to default values.
10480 sc -> video_avcc = avcodec_alloc_context3 (sc -> video_avc );
10581 if (!sc -> video_avcc ) {logging ("could not allocated memory for codec context" ); return -1 ;}
10682
10783 av_opt_set (sc -> video_avcc -> priv_data , "preset" , "slow" , 0 );
10884 av_opt_set (sc -> video_avcc -> priv_data , "x264opts" , "keyint=60:min-keyint=60:scenecut=-1" , 0 );
109- //
110- //sc->video_avcc->keyint_min = 60;
111- //sc->video_avcc->gop_size = 60;
11285
11386 sc -> video_avcc -> height = decoder_ctx -> height ;
11487 sc -> video_avcc -> width = decoder_ctx -> width ;
115- //sc->video_avcc->sample_aspect_ratio = decoder_ctx->sample_aspect_ratio;
116-
117- // set up pixel format
11888 if (sc -> video_avc -> pix_fmts )
11989 sc -> video_avcc -> pix_fmt = sc -> video_avc -> pix_fmts [0 ];
12090 else
12191 sc -> video_avcc -> pix_fmt = decoder_ctx -> pix_fmt ;
122-
12392 sc -> video_avcc -> time_base = input_framerate ;
124- //sc->video_avcc->time_base = (AVRational){1,1};
125-
126- //print_timing("Video encoder 1", sc->avfc, sc->video_avcc, sc->video_avs);
12793 sc -> video_avs -> time_base = input_framerate ;
12894
129-
130- AVDictionary * encoder_private_options = NULL ;
131- // TODO: understand the difference between this and ->priv_data
132- //av_dict_set(&encoder_private_options , "b", "2.0M", 0);
133- // is this related to http://www.chaneru.com/Roku/HLS/X264_Settings.htm ?
134-
135- //https://www.ffmpeg.org/doxygen/trunk/group__lavc__core.html#ga11f785a188d7d9df71621001465b0f1d
136- // Initialize the AVCodecContext to use the given AVCodec. (does it resets the avcc?)
137- if (avcodec_open2 (sc -> video_avcc , sc -> video_avc , & encoder_private_options ) < 0 ) {logging ("could not open the codec" ); return -1 ;}
138- //print_timing("Video encoder 2", sc->avfc, sc->video_avcc, sc->video_avs);
139-
140- //https://www.ffmpeg.org/doxygen/trunk/group__lavc__core.html#ga0c7058f764778615e7978a1821ab3cfe
141- // Fill the parameters struct based on the values from the supplied codec context.
95+ if (avcodec_open2 (sc -> video_avcc , sc -> video_avc , NULL ) < 0 ) {logging ("could not open the codec" ); return -1 ;}
14296 avcodec_parameters_from_context (sc -> video_avs -> codecpar , sc -> video_avcc );
143- // TODO: I want to base my setting on the decoder but I'm copying from my encoder
144- //print_timing("Video encoder 3", sc->avfc, sc->video_avcc, sc->video_avs);
145-
14697 return 0 ;
14798}
14899
149100int prepare_copy (AVFormatContext * avfc , AVStream * * avs , AVCodecParameters * decoder_par ) {
150101 * avs = avformat_new_stream (avfc , NULL );
151- //https://www.ffmpeg.org/doxygen/trunk/group__lavc__core.html#ga6d02e640ccc12c783841ce51d09b9fa7
152- // Any allocated fields in dst are freed and replaced with newly allocated duplicates of the corresponding fields in src.
153102 avcodec_parameters_copy ((* avs )-> codecpar , decoder_par );
154103 return 0 ;
155104}
156105
157106int remux (AVPacket * * pkt , AVFormatContext * * avfc , AVRational decoder_tb , AVRational encoder_tb ) {
158- //https://www.ffmpeg.org/doxygen/trunk/group__lavc__packet.html#gae5c86e4d93f6e7aa62ef2c60763ea67e
159- // Convert valid timing fields (timestamps / durations) in a packet from one timebase to another.
160107 av_packet_rescale_ts (* pkt , decoder_tb , encoder_tb );
161-
162- //https://www.ffmpeg.org/doxygen/trunk/group__lavf__encoding.html#ga37352ed2c63493c38219d935e71db6c1
163- // Write a packet to an output media file ensuring correct interleaving
164108 if (av_interleaved_write_frame (* avfc , * pkt ) < 0 ) { logging ("error while copying stream packet" ); return -1 ; }
165109 return 0 ;
166110}
@@ -169,13 +113,9 @@ int encode(StreamingContext *decoder, StreamingContext *encoder, AVFrame *input_
169113 AVPacket * output_packet = av_packet_alloc ();
170114 if (!output_packet ) {logging ("could not allocate memory for output packet" ); return -1 ;}
171115
172- //https://www.ffmpeg.org/doxygen/trunk/group__lavc__decoding.html#ga9395cb802a5febf1f00df31497779169
173- // Supply a raw video or audio frame to the encoder.
174116 int response = avcodec_send_frame (encoder -> video_avcc , input_frame );
175117
176118 while (response >= 0 ) {
177- //https://www.ffmpeg.org/doxygen/trunk/group__lavc__decoding.html#ga5b8eff59cf259747cf0b31563e38ded6
178- // Read encoded data from the encoder.
179119 response = avcodec_receive_packet (encoder -> video_avcc , output_packet );
180120 if (response == AVERROR (EAGAIN ) || response == AVERROR_EOF ) {
181121 break ;
@@ -184,42 +124,23 @@ int encode(StreamingContext *decoder, StreamingContext *encoder, AVFrame *input_
184124 return -1 ;
185125 }
186126
187- /* prepare packet for muxing */
188- //output_packet->stream_index = input_packet->stream_index; // ??????????????????? decoder->video_index
189- output_packet -> stream_index = decoder -> video_index ; // ??????????????????? decoder->video_index
190- // you need to set the package duration otherwise
191- // it might present fps/dts/pts issues (thanks James and Vassilis from mailing list)
127+ output_packet -> stream_index = decoder -> video_index ;
192128 output_packet -> duration = encoder -> video_avs -> time_base .den / encoder -> video_avs -> time_base .num / decoder -> video_avs -> avg_frame_rate .num * decoder -> video_avs -> avg_frame_rate .den ;
193129
194- //output_packet->stream_index = input_packet->stream_index;
195- //https://www.ffmpeg.org/doxygen/trunk/group__lavc__packet.html#gae5c86e4d93f6e7aa62ef2c60763ea67e
196- // Convert valid timing fields (timestamps / durations) in a packet from one timebase to another.
197130 av_packet_rescale_ts (output_packet , decoder -> video_avs -> time_base , encoder -> video_avs -> time_base );
198- //output_packet->stream_index = input_packet->stream_index; ?????????????
199-
200- //https://www.ffmpeg.org/doxygen/trunk/group__lavf__encoding.html#ga37352ed2c63493c38219d935e71db6c1
201- // Write a packet to an output media file ensuring correct interleaving.
202131 response = av_interleaved_write_frame (encoder -> avfc , output_packet );
203132 if (response != 0 ) { logging ("Error %d while receiving packet from decoder: %s" , response , av_err2str (response )); return -1 ;}
204133 }
205134 av_packet_unref (output_packet );
206135 av_packet_free (& output_packet );
207-
208136 return 0 ;
209137}
210138
211139int transcode (StreamingContext * decoder , StreamingContext * encoder , AVPacket * input_packet , AVFrame * input_frame ) {
212- /*
213- * Decoding video stream so we can re-encode it
214- */
215- //https://www.ffmpeg.org/doxygen/trunk/group__lavc__decoding.html#ga58bc4bf1e0ac59e27362597e467efff3
216- // Supply raw packet data as input to a decoder.
217140 int response = avcodec_send_packet (decoder -> video_avcc , input_packet );
218141 if (response < 0 ) {logging ("Error while sending packet to decoder: %s" , av_err2str (response )); return response ;}
219142
220143 while (response >= 0 ) {
221- //https://www.ffmpeg.org/doxygen/trunk/group__lavc__decoding.html#ga11e6542c4e66d3028668788a1a74217c
222- // Return decoded output data from a decoder.
223144 response = avcodec_receive_frame (decoder -> video_avcc , input_frame );
224145 if (response == AVERROR (EAGAIN ) || response == AVERROR_EOF ) {
225146 break ;
@@ -228,9 +149,6 @@ int transcode(StreamingContext *decoder, StreamingContext *encoder, AVPacket *in
228149 return response ;
229150 }
230151
231- /*
232- * Re-encoding the frame since it was decoded successfully
233- */
234152 if (response >= 0 ) {
235153 if (encode (decoder , encoder , input_frame )) return -1 ;
236154 }
@@ -241,7 +159,6 @@ int transcode(StreamingContext *decoder, StreamingContext *encoder, AVPacket *in
241159
242160int main (int argc , char * argv [])
243161{
244- //av_log_set_level(AV_LOG_DEBUG);
245162 StreamingParams sp = {0 };
246163 sp .copy_audio = 1 ;
247164 sp .copy_video = 0 ;
@@ -253,120 +170,71 @@ int main(int argc, char *argv[])
253170 StreamingContext * encoder = (StreamingContext * ) calloc (1 , sizeof (StreamingContext ));
254171 encoder -> filename = argv [2 ];
255172
256- /*
257- * Opening the decodable media file
258- */
259173 if (open_media (decoder -> filename , & decoder -> avfc )) return -1 ;
260-
261- /*
262- * Prepping the decoder
263- */
264174 if (prepare_decoder (decoder )) return -1 ;
265175
266- /*
267- * Opening the output media file
268- */
269- //https://www.ffmpeg.org/doxygen/trunk/avformat_8h.html#a0234fa1116af3c0a72edaa08a2ba304f
270- // Allocate an AVFormatContext for an output format.
271176 avformat_alloc_output_context2 (& encoder -> avfc , NULL , NULL , encoder -> filename );
272177 if (!encoder -> avfc ) {logging ("could not allocate memory for output format" );return -1 ;}
273178
274- /*
275- * Prepping the encoder
276- */
277-
278- // for video
279179 if (!sp .copy_video ) {
280- // transcoding
281180 AVRational input_framerate = av_guess_frame_rate (decoder -> avfc , decoder -> video_avs , NULL );
282181 prepare_encoder (encoder , decoder -> video_avcc , input_framerate );
283182 } else {
284- // just copying
285183 if (prepare_copy (encoder -> avfc , & encoder -> video_avs , decoder -> video_avs -> codecpar )) {return -1 ;}
286184 }
287185
288- // for audio
289186 if (!sp .copy_audio ) {
290187 // transcoding
291- // TODO:
292188 } else {
293- // just copying
294189 if (prepare_copy (encoder -> avfc , & encoder -> audio_avs , decoder -> audio_avs -> codecpar )) {return -1 ;}
295190 }
296191
297- /*
298- * Prepping the output media file
299- */
300192 if (encoder -> avfc -> oformat -> flags & AVFMT_GLOBALHEADER )
301- //https://www.ffmpeg.org/doxygen/trunk/group__lavc__core.html#ga9ed82634c59b339786575827c47a8f68
302- // Place global headers in extradata instead of every keyframe.
303193 encoder -> avfc -> flags |= AV_CODEC_FLAG_GLOBAL_HEADER ;
304194
305195 if (!(encoder -> avfc -> oformat -> flags & AVFMT_NOFILE )) {
306- //https://www.ffmpeg.org/doxygen/trunk/aviobuf_8c.html#ab1b99c5b70aa59f15ab7cd4cbb40381e
307- // Create and initialize a AVIOContext for accessing the resource indicated by url.
308196 if (avio_open (& encoder -> avfc -> pb , encoder -> filename , AVIO_FLAG_WRITE ) < 0 ) {
309197 logging ("could not open the output file" );
310198 return -1 ;
311199 }
312200 }
313201
314- // adding options to the muxer
315202 AVDictionary * muxer_opts = NULL ;
316203
317204 if (sp .fragmented_mp4 ) {
318- // https://developer.mozilla.org/en-US/docs/Web/API/Media_Source_Extensions_API/Transcoding_assets_for_MSE
319205 av_dict_set (& muxer_opts , "movflags" , "frag_keyframe+empty_moov+default_base_moof" , 0 );
320206 }
321207
322- //https://www.ffmpeg.org/doxygen/trunk/group__lavf__encoding.html#ga18b7b10bb5b94c4842de18166bc677cb
323- // Allocate the stream private data and write the stream header to an output media file.
324208 if (avformat_write_header (encoder -> avfc , & muxer_opts ) < 0 ) {logging ("an error occurred when opening output file" ); return -1 ;}
325209
326- /*
327- * Reading the streams packets from the input media file
328- */
329210 AVFrame * input_frame = av_frame_alloc ();
330211 if (!input_frame ) {logging ("failed to allocated memory for AVFrame" ); return -1 ;}
331212
332213 AVPacket * input_packet = av_packet_alloc ();
333214 if (!input_packet ) {logging ("failed to allocated memory for AVPacket" ); return -1 ;}
334215
335- //https://www.ffmpeg.org/doxygen/trunk/group__lavf__decoding.html#ga4fdb3084415a82e3810de6ee60e46a61
336- // Return the next frame of a stream.
337216 while (av_read_frame (decoder -> avfc , input_packet ) >= 0 )
338217 {
339218 if (decoder -> avfc -> streams [input_packet -> stream_index ]-> codecpar -> codec_type == AVMEDIA_TYPE_VIDEO ) {
340219 if (!sp .copy_video ) {
341- // transcoding
342220 if (transcode (decoder , encoder , input_packet , input_frame )) return -1 ;
343- av_packet_unref (input_packet ); // TODO: should I add this for all?
221+ av_packet_unref (input_packet );
344222 } else {
345- // just copying
346223 if (remux (& input_packet , & encoder -> avfc , decoder -> video_avs -> time_base , encoder -> video_avs -> time_base )) return -1 ;
347224 }
348225 } else if (decoder -> avfc -> streams [input_packet -> stream_index ]-> codecpar -> codec_type == AVMEDIA_TYPE_AUDIO ) {
349226 if (!sp .copy_audio ) {
350- // transcoding
351227 // TODO
352228 } else {
353- // just copying
354229 if (remux (& input_packet , & encoder -> avfc , decoder -> audio_avs -> time_base , encoder -> audio_avs -> time_base )) return -1 ;
355- //av_packet_free(&input_packet);
356230 }
357231 } else {
358232 logging ("ignoring all non video or audio packets" );
359233 }
360234 }
361- // to flush ?????????
362235 if (encode (decoder , encoder , NULL )) return -1 ;
363236
364-
365-
366- //https://www.ffmpeg.org/doxygen/trunk/group__lavf__encoding.html#ga7f14007e7dc8f481f054b21614dfec13
367- // Write the stream trailer to an output media file and free the file private data.
368237 av_write_trailer (encoder -> avfc );
369-
370238 // TODO: we should free everything!
371239 return 0 ;
372240}
0 commit comments