164 FatalError("Error while writing audio frame"); |
179 FatalError("Error while writing audio frame"); |
165 return 1; |
180 return 1; |
166 } |
181 } |
167 |
182 |
168 // add a video output stream |
183 // add a video output stream |
169 static void AddVideoStream(enum CodecID codec_id) |
184 static void AddVideoStream() |
170 { |
185 { |
171 #if LIBAVCODEC_VERSION_MAJOR >= 54 |
186 #if LIBAVCODEC_VERSION_MAJOR >= 54 |
172 g_pVStream = avformat_new_stream(g_pContainer, g_pVCodec); |
187 g_pVStream = avformat_new_stream(g_pContainer, g_pVCodec); |
173 #else |
188 #else |
174 g_pVStream = av_new_stream(g_pContainer, 0); |
189 g_pVStream = av_new_stream(g_pContainer, 0); |
175 #endif |
190 #endif |
176 if (!g_pVStream) |
191 if (!g_pVStream) |
177 FatalError("Could not allocate video stream"); |
192 FatalError("Could not allocate video stream"); |
178 |
193 |
179 g_pVideo = g_pVStream->codec; |
194 g_pVideo = g_pVStream->codec; |
180 avcodec_get_context_defaults3( g_pVideo, g_pVCodec ); |
195 |
181 g_pVideo->codec_id = codec_id; |
196 avcodec_get_context_defaults3(g_pVideo, g_pVCodec); |
|
197 g_pVideo->codec_id = g_pVCodec->id; |
182 |
198 |
183 // put parameters |
199 // put parameters |
184 // resolution must be a multiple of two |
200 // resolution must be a multiple of two |
185 g_pVideo->width = g_Width; |
201 g_pVideo->width = g_Width; |
186 g_pVideo->height = g_Height; |
202 g_pVideo->height = g_Height; |
187 /* time base: this is the fundamental unit of time (in seconds) in terms |
203 /* time base: this is the fundamental unit of time (in seconds) in terms |
188 of which frame timestamps are represented. for fixed-fps content, |
204 of which frame timestamps are represented. for fixed-fps content, |
189 timebase should be 1/framerate and timestamp increments should be |
205 timebase should be 1/framerate and timestamp increments should be |
190 identically 1. */ |
206 identically 1. */ |
191 g_pVideo->time_base.den = g_Framerate; |
207 g_pVideo->time_base.den = g_Framerate.num; |
192 g_pVideo->time_base.num = 1; |
208 g_pVideo->time_base.num = g_Framerate.den; |
193 //g_pVideo->gop_size = 12; /* emit one intra frame every twelve frames at most */ |
209 //g_pVideo->gop_size = 12; /* emit one intra frame every twelve frames at most */ |
194 g_pVideo->pix_fmt = PIX_FMT_YUV420P; |
210 g_pVideo->pix_fmt = PIX_FMT_YUV420P; |
|
211 |
|
212 // set quality |
|
213 if (g_VQuality > 100) |
|
214 g_pVideo->bit_rate = g_VQuality; |
|
215 else |
|
216 { |
|
217 g_pVideo->flags |= CODEC_FLAG_QSCALE; |
|
218 g_pVideo->global_quality = g_VQuality*FF_QP2LAMBDA; |
|
219 } |
|
220 |
|
221 AVDictionary* pDict = NULL; |
|
222 if (strcmp(g_pVCodec->name, "libx264") == 0) |
|
223 av_dict_set(&pDict, "preset", g_pPreset, 0); |
195 |
224 |
196 // some formats want stream headers to be separate |
225 // some formats want stream headers to be separate |
197 if (g_pFormat->flags & AVFMT_GLOBALHEADER) |
226 if (g_pFormat->flags & AVFMT_GLOBALHEADER) |
198 g_pVideo->flags |= CODEC_FLAG_GLOBAL_HEADER; |
227 g_pVideo->flags |= CODEC_FLAG_GLOBAL_HEADER; |
199 |
|
200 AVDictionary* pDict = NULL; |
|
201 if (codec_id == CODEC_ID_H264) |
|
202 { |
|
203 // av_dict_set(&pDict, "tune", "animation", 0); |
|
204 // av_dict_set(&pDict, "preset", "veryslow", 0); |
|
205 av_dict_set(&pDict, "crf", "20", 0); |
|
206 } |
|
207 else |
|
208 { |
|
209 g_pVideo->flags |= CODEC_FLAG_QSCALE; |
|
210 // g_pVideo->bit_rate = g_Width*g_Height*g_Framerate/4; |
|
211 g_pVideo->global_quality = 15*FF_QP2LAMBDA; |
|
212 } |
|
213 |
228 |
214 // open the codec |
229 // open the codec |
215 if (avcodec_open2(g_pVideo, g_pVCodec, &pDict) < 0) |
230 if (avcodec_open2(g_pVideo, g_pVCodec, &pDict) < 0) |
216 FatalError("Could not open video codec %s", g_pVCodec->long_name); |
231 FatalError("Could not open video codec %s", g_pVCodec->long_name); |
217 |
232 |
298 g_pVFrame->data[1] = pCb; |
316 g_pVFrame->data[1] = pCb; |
299 g_pVFrame->data[2] = pCr; |
317 g_pVFrame->data[2] = pCr; |
300 WriteFrame(g_pVFrame); |
318 WriteFrame(g_pVFrame); |
301 } |
319 } |
302 |
320 |
303 void AVWrapper_GetList() |
321 void AVWrapper_Init( |
304 { |
322 void (*pAddFileLogRaw)(const char*), |
305 // initialize libav and register all codecs and formats |
323 const char* pFilename, |
306 av_register_all(); |
324 const char* pSoundFile, |
307 |
325 const char* pFormatName, |
308 #if 0 |
326 const char* pVCodecName, |
309 AVOutputFormat* pFormat = NULL; |
327 const char* pACodecName, |
310 while (pFormat = av_oformat_next(pFormat)) |
328 const char* pVPreset, |
311 { |
329 int Width, int Height, |
312 Log("%s; %s; %s;\n", pFormat->name, pFormat->long_name, pFormat->mime_type); |
330 int FramerateNum, int FramerateDen, |
313 |
331 int Frequency, int Channels, |
314 AVCodec* pCodec = NULL; |
332 int VQuality, int AQuality) |
315 while (pCodec = av_codec_next(pCodec)) |
|
316 { |
|
317 if (!av_codec_is_encoder(pCodec)) |
|
318 continue; |
|
319 if (avformat_query_codec(pFormat, pCodec->id, FF_COMPLIANCE_NORMAL) != 1) |
|
320 continue; |
|
321 if (pCodec->type = AVMEDIA_TYPE_VIDEO) |
|
322 { |
|
323 if (pCodec->supported_framerate != NULL) |
|
324 continue; |
|
325 Log(" Video: %s; %s;\n", pCodec->name, pCodec->long_name); |
|
326 } |
|
327 if (pCodec->type = AVMEDIA_TYPE_AUDIO) |
|
328 { |
|
329 /* if (pCodec->supported_samplerates == NULL) |
|
330 continue; |
|
331 int i; |
|
332 for(i = 0; i <) |
|
333 supported_samplerates*/ |
|
334 Log(" Audio: %s; %s;\n", pCodec->name, pCodec->long_name); |
|
335 } |
|
336 } |
|
337 /* struct AVCodecTag** pTags = pCur->codec_tag; |
|
338 int i; |
|
339 for (i = 0; ; i++) |
|
340 { |
|
341 enum CodecID id = av_codec_get_id(pTags, i); |
|
342 if (id == CODEC_ID_NONE) |
|
343 break; |
|
344 AVCodec* pCodec = avcodec_find_encoder(id); |
|
345 Log(" %i: %s; %s;\n", id, pCodec->name, pCodec->long_name); |
|
346 }*/ |
|
347 } |
|
348 #endif |
|
349 } |
|
350 |
|
351 void AVWrapper_Init(void (*pAddFileLogRaw)(const char*), const char* pFilename, const char* pSoundFile, int Width, int Height, int Framerate, int Frequency, int Channels) |
|
352 { |
333 { |
353 AddFileLogRaw = pAddFileLogRaw; |
334 AddFileLogRaw = pAddFileLogRaw; |
354 av_log_set_callback( &LogCallback ); |
335 av_log_set_callback( &LogCallback ); |
355 |
336 |
356 g_Width = Width; |
337 g_Width = Width; |
357 g_Height = Height; |
338 g_Height = Height; |
358 g_Framerate = Framerate; |
339 g_Framerate.num = FramerateNum; |
|
340 g_Framerate.den = FramerateDen; |
359 g_Frequency = Frequency; |
341 g_Frequency = Frequency; |
360 g_Channels = Channels; |
342 g_Channels = Channels; |
|
343 g_VQuality = VQuality; |
|
344 g_AQuality = AQuality; |
|
345 g_pPreset = pVPreset; |
361 |
346 |
362 // initialize libav and register all codecs and formats |
347 // initialize libav and register all codecs and formats |
363 av_register_all(); |
348 av_register_all(); |
364 |
349 |
365 AVWrapper_GetList(); |
350 // find format |
366 |
351 g_pFormat = av_guess_format(pFormatName, NULL, NULL); |
367 // allocate the output media context |
|
368 #if LIBAVCODEC_VERSION_MAJOR >= 54 |
|
369 avformat_alloc_output_context2(&g_pContainer, NULL, "mp4", pFilename); |
|
370 #else |
|
371 g_pFormat = av_guess_format(NULL, pFilename, NULL); |
|
372 if (!g_pFormat) |
352 if (!g_pFormat) |
373 FatalError("guess_format"); |
353 FatalError("Format \"%s\" was not found", pFormatName); |
374 |
354 |
375 // allocate the output media context |
355 // allocate the output media context |
376 g_pContainer = avformat_alloc_context(); |
356 g_pContainer = avformat_alloc_context(); |
377 if (g_pContainer) |
|
378 { |
|
379 g_pContainer->oformat = g_pFormat; |
|
380 snprintf(g_pContainer->filename, sizeof(g_pContainer->filename), "%s", pFilename); |
|
381 } |
|
382 #endif |
|
383 if (!g_pContainer) |
357 if (!g_pContainer) |
384 FatalError("Could not allocate output context"); |
358 FatalError("Could not allocate output context"); |
385 |
359 |
386 g_pFormat = g_pContainer->oformat; |
360 g_pContainer->oformat = g_pFormat; |
387 |
361 |
388 enum CodecID VideoCodecID = g_pFormat->video_codec;//CODEC_ID_H264; |
362 // append extesnion to filename |
389 enum CodecID AudioCodecID = g_pFormat->audio_codec; |
363 snprintf(g_pContainer->filename, sizeof(g_pContainer->filename), |
390 |
364 "%s.%*s", |
|
365 pFilename, |
|
366 strcspn(g_pFormat->extensions, ","), g_pFormat->extensions); |
|
367 |
|
368 // find codecs |
|
369 g_pVCodec = avcodec_find_encoder_by_name(pVCodecName); |
|
370 g_pACodec = avcodec_find_encoder_by_name(pACodecName); |
|
371 |
|
372 // add audio and video stream to container |
391 g_pVStream = NULL; |
373 g_pVStream = NULL; |
392 g_pAStream = NULL; |
374 g_pAStream = NULL; |
393 if (VideoCodecID != CODEC_ID_NONE) |
375 |
394 { |
376 if (g_pVCodec) |
395 g_pVCodec = avcodec_find_encoder(VideoCodecID); |
377 AddVideoStream(); |
396 if (!g_pVCodec) |
378 else |
397 FatalError("Video codec not found"); |
379 Log("Video codec \"%s\" was not found; video will be ignored.\n", pVCodecName); |
398 AddVideoStream(VideoCodecID); |
380 |
399 } |
381 if (g_pACodec) |
400 |
382 AddAudioStream(); |
401 if (AudioCodecID != CODEC_ID_NONE) |
383 else |
402 { |
384 Log("Audio codec \"%s\" was not found; audio will be ignored.\n", pACodecName); |
403 g_pACodec = avcodec_find_encoder(AudioCodecID); |
385 |
404 if (!g_pACodec) |
386 if (!g_pAStream && !g_pVStream) |
405 FatalError("Audio codec not found"); |
387 FatalError("No video, no audio, aborting..."); |
406 AddAudioStream(AudioCodecID); |
|
407 } |
|
408 |
388 |
409 if (g_pAStream) |
389 if (g_pAStream) |
410 { |
390 { |
411 g_pSoundFile = fopen(pSoundFile, "rb"); |
391 g_pSoundFile = fopen(pSoundFile, "rb"); |
412 if (!g_pSoundFile) |
392 if (!g_pSoundFile) |
413 FatalError("Could not open %s", pSoundFile); |
393 FatalError("Could not open %s", pSoundFile); |
414 } |
394 } |
415 |
395 |
416 // write format info to log |
396 // write format info to log |
417 av_dump_format(g_pContainer, 0, pFilename, 1); |
397 av_dump_format(g_pContainer, 0, g_pContainer->filename, 1); |
418 |
398 |
419 // open the output file, if needed |
399 // open the output file, if needed |
420 if (!(g_pFormat->flags & AVFMT_NOFILE)) |
400 if (!(g_pFormat->flags & AVFMT_NOFILE)) |
421 { |
401 { |
422 if (avio_open(&g_pContainer->pb, pFilename, AVIO_FLAG_WRITE) < 0) |
402 if (avio_open(&g_pContainer->pb, g_pContainer->filename, AVIO_FLAG_WRITE) < 0) |
423 FatalError("Could not open output file (%s)", pFilename); |
403 FatalError("Could not open output file (%s)", pFilename); |
424 } |
404 } |
425 |
405 |
426 // write the stream header, if any |
406 // write the stream header, if any |
427 avformat_write_header(g_pContainer, NULL); |
407 avformat_write_header(g_pContainer, NULL); |
|
408 |
428 g_pVFrame->pts = -1; |
409 g_pVFrame->pts = -1; |
429 } |
410 } |
430 |
411 |
431 void AVWrapper_Close() |
412 void AVWrapper_Close() |
432 { |
413 { |