1 /* |
|
2 * Hedgewars, a free turn based strategy game |
|
3 * Copyright (c) 2004-2013 Andrey Korotaev <unC0Rr@gmail.com> |
|
4 * |
|
5 * This program is free software; you can redistribute it and/or modify |
|
6 * it under the terms of the GNU General Public License as published by |
|
7 * the Free Software Foundation; version 2 of the License |
|
8 * |
|
9 * This program is distributed in the hope that it will be useful, |
|
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
12 * GNU General Public License for more details. |
|
13 * |
|
14 * You should have received a copy of the GNU General Public License |
|
15 * along with this program; if not, write to the Free Software |
|
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA |
|
17 */ |
|
18 |
|
19 #include <stdlib.h> |
|
20 #include <stdio.h> |
|
21 #include <stdint.h> |
|
22 #include <string.h> |
|
23 #include <stdarg.h> |
|
24 #include "libavformat/avformat.h" |
|
25 #include "libavutil/mathematics.h" |
|
26 |
|
27 #ifndef AVIO_FLAG_WRITE |
|
28 #define AVIO_FLAG_WRITE AVIO_WRONLY |
|
29 #endif |
|
30 |
|
31 #if (defined _MSC_VER) |
|
32 #define AVWRAP_DECL __declspec(dllexport) |
|
33 #elif ((__GNUC__ >= 3) && (!__EMX__) && (!sun)) |
|
34 #define AVWRAP_DECL __attribute__((visibility("default"))) |
|
35 #else |
|
36 #define AVWRAP_DECL |
|
37 #endif |
|
38 |
|
39 static AVFormatContext* g_pContainer; |
|
40 static AVOutputFormat* g_pFormat; |
|
41 static AVStream* g_pAStream; |
|
42 static AVStream* g_pVStream; |
|
43 static AVFrame* g_pAFrame; |
|
44 static AVFrame* g_pVFrame; |
|
45 static AVCodec* g_pACodec; |
|
46 static AVCodec* g_pVCodec; |
|
47 static AVCodecContext* g_pAudio; |
|
48 static AVCodecContext* g_pVideo; |
|
49 |
|
50 static int g_Width, g_Height; |
|
51 static uint32_t g_Frequency, g_Channels; |
|
52 static int g_VQuality; |
|
53 static AVRational g_Framerate; |
|
54 |
|
55 static FILE* g_pSoundFile; |
|
56 static int16_t* g_pSamples; |
|
57 static int g_NumSamples; |
|
58 |
|
59 |
|
60 #if LIBAVCODEC_VERSION_MAJOR < 54 |
|
61 #define OUTBUFFER_SIZE 200000 |
|
62 static uint8_t g_OutBuffer[OUTBUFFER_SIZE]; |
|
63 #endif |
|
64 |
|
65 // pointer to function from hwengine (uUtils.pas) |
|
66 static void (*AddFileLogRaw)(const char* pString); |
|
67 |
|
68 static void FatalError(const char* pFmt, ...) |
|
69 { |
|
70 char Buffer[1024]; |
|
71 va_list VaArgs; |
|
72 |
|
73 va_start(VaArgs, pFmt); |
|
74 vsnprintf(Buffer, 1024, pFmt, VaArgs); |
|
75 va_end(VaArgs); |
|
76 |
|
77 AddFileLogRaw("Error in av-wrapper: "); |
|
78 AddFileLogRaw(Buffer); |
|
79 AddFileLogRaw("\n"); |
|
80 exit(1); |
|
81 } |
|
82 |
|
83 // Function to be called from libav for logging. |
|
84 // Note: libav can call LogCallback from different threads |
|
85 // (there is mutex in AddFileLogRaw). |
|
86 static void LogCallback(void* p, int Level, const char* pFmt, va_list VaArgs) |
|
87 { |
|
88 char Buffer[1024]; |
|
89 |
|
90 vsnprintf(Buffer, 1024, pFmt, VaArgs); |
|
91 AddFileLogRaw(Buffer); |
|
92 } |
|
93 |
|
94 static void Log(const char* pFmt, ...) |
|
95 { |
|
96 char Buffer[1024]; |
|
97 va_list VaArgs; |
|
98 |
|
99 va_start(VaArgs, pFmt); |
|
100 vsnprintf(Buffer, 1024, pFmt, VaArgs); |
|
101 va_end(VaArgs); |
|
102 |
|
103 AddFileLogRaw(Buffer); |
|
104 } |
|
105 |
|
106 static void AddAudioStream() |
|
107 { |
|
108 #if LIBAVFORMAT_VERSION_MAJOR >= 53 |
|
109 g_pAStream = avformat_new_stream(g_pContainer, g_pACodec); |
|
110 #else |
|
111 g_pAStream = av_new_stream(g_pContainer, 1); |
|
112 #endif |
|
113 if(!g_pAStream) |
|
114 { |
|
115 Log("Could not allocate audio stream\n"); |
|
116 return; |
|
117 } |
|
118 g_pAStream->id = 1; |
|
119 |
|
120 g_pAudio = g_pAStream->codec; |
|
121 |
|
122 avcodec_get_context_defaults3(g_pAudio, g_pACodec); |
|
123 g_pAudio->codec_id = g_pACodec->id; |
|
124 |
|
125 // put parameters |
|
126 g_pAudio->sample_fmt = AV_SAMPLE_FMT_S16; |
|
127 g_pAudio->sample_rate = g_Frequency; |
|
128 g_pAudio->channels = g_Channels; |
|
129 |
|
130 // set quality |
|
131 g_pAudio->bit_rate = 160000; |
|
132 |
|
133 // for codecs that support variable bitrate use it, it should be better |
|
134 g_pAudio->flags |= CODEC_FLAG_QSCALE; |
|
135 g_pAudio->global_quality = 1*FF_QP2LAMBDA; |
|
136 |
|
137 // some formats want stream headers to be separate |
|
138 if (g_pFormat->flags & AVFMT_GLOBALHEADER) |
|
139 g_pAudio->flags |= CODEC_FLAG_GLOBAL_HEADER; |
|
140 |
|
141 // open it |
|
142 #if LIBAVCODEC_VERSION_MAJOR >= 53 |
|
143 if (avcodec_open2(g_pAudio, g_pACodec, NULL) < 0) |
|
144 #else |
|
145 if (avcodec_open(g_pAudio, g_pACodec) < 0) |
|
146 #endif |
|
147 { |
|
148 Log("Could not open audio codec %s\n", g_pACodec->long_name); |
|
149 return; |
|
150 } |
|
151 |
|
152 #if LIBAVCODEC_VERSION_MAJOR >= 54 |
|
153 if (g_pACodec->capabilities & CODEC_CAP_VARIABLE_FRAME_SIZE) |
|
154 #else |
|
155 if (g_pAudio->frame_size == 0) |
|
156 #endif |
|
157 g_NumSamples = 4096; |
|
158 else |
|
159 g_NumSamples = g_pAudio->frame_size; |
|
160 g_pSamples = (int16_t*)av_malloc(g_NumSamples*g_Channels*sizeof(int16_t)); |
|
161 g_pAFrame = avcodec_alloc_frame(); |
|
162 if (!g_pAFrame) |
|
163 { |
|
164 Log("Could not allocate frame\n"); |
|
165 return; |
|
166 } |
|
167 } |
|
168 |
|
169 // returns non-zero if there is more sound |
|
170 static int WriteAudioFrame() |
|
171 { |
|
172 if (!g_pAStream) |
|
173 return 0; |
|
174 |
|
175 AVPacket Packet = { 0 }; |
|
176 av_init_packet(&Packet); |
|
177 |
|
178 int NumSamples = fread(g_pSamples, 2*g_Channels, g_NumSamples, g_pSoundFile); |
|
179 |
|
180 #if LIBAVCODEC_VERSION_MAJOR >= 53 |
|
181 AVFrame* pFrame = NULL; |
|
182 if (NumSamples > 0) |
|
183 { |
|
184 g_pAFrame->nb_samples = NumSamples; |
|
185 avcodec_fill_audio_frame(g_pAFrame, g_Channels, AV_SAMPLE_FMT_S16, |
|
186 (uint8_t*)g_pSamples, NumSamples*2*g_Channels, 1); |
|
187 pFrame = g_pAFrame; |
|
188 } |
|
189 // when NumSamples == 0 we still need to call encode_audio2 to flush |
|
190 int got_packet; |
|
191 if (avcodec_encode_audio2(g_pAudio, &Packet, pFrame, &got_packet) != 0) |
|
192 FatalError("avcodec_encode_audio2 failed"); |
|
193 if (!got_packet) |
|
194 return 0; |
|
195 #else |
|
196 if (NumSamples == 0) |
|
197 return 0; |
|
198 int BufferSize = OUTBUFFER_SIZE; |
|
199 if (g_pAudio->frame_size == 0) |
|
200 BufferSize = NumSamples*g_Channels*2; |
|
201 Packet.size = avcodec_encode_audio(g_pAudio, g_OutBuffer, BufferSize, g_pSamples); |
|
202 if (Packet.size == 0) |
|
203 return 1; |
|
204 if (g_pAudio->coded_frame && g_pAudio->coded_frame->pts != AV_NOPTS_VALUE) |
|
205 Packet.pts = av_rescale_q(g_pAudio->coded_frame->pts, g_pAudio->time_base, g_pAStream->time_base); |
|
206 Packet.flags |= AV_PKT_FLAG_KEY; |
|
207 Packet.data = g_OutBuffer; |
|
208 #endif |
|
209 |
|
210 // Write the compressed frame to the media file. |
|
211 Packet.stream_index = g_pAStream->index; |
|
212 if (av_interleaved_write_frame(g_pContainer, &Packet) != 0) |
|
213 FatalError("Error while writing audio frame"); |
|
214 return 1; |
|
215 } |
|
216 |
|
217 // add a video output stream |
|
218 static void AddVideoStream() |
|
219 { |
|
220 #if LIBAVFORMAT_VERSION_MAJOR >= 53 |
|
221 g_pVStream = avformat_new_stream(g_pContainer, g_pVCodec); |
|
222 #else |
|
223 g_pVStream = av_new_stream(g_pContainer, 0); |
|
224 #endif |
|
225 if (!g_pVStream) |
|
226 FatalError("Could not allocate video stream"); |
|
227 |
|
228 g_pVideo = g_pVStream->codec; |
|
229 |
|
230 avcodec_get_context_defaults3(g_pVideo, g_pVCodec); |
|
231 g_pVideo->codec_id = g_pVCodec->id; |
|
232 |
|
233 // put parameters |
|
234 // resolution must be a multiple of two |
|
235 g_pVideo->width = g_Width & ~1; // make even (dimensions should be even) |
|
236 g_pVideo->height = g_Height & ~1; // make even |
|
237 /* time base: this is the fundamental unit of time (in seconds) in terms |
|
238 of which frame timestamps are represented. for fixed-fps content, |
|
239 timebase should be 1/framerate and timestamp increments should be |
|
240 identically 1. */ |
|
241 g_pVideo->time_base.den = g_Framerate.num; |
|
242 g_pVideo->time_base.num = g_Framerate.den; |
|
243 //g_pVideo->gop_size = 12; /* emit one intra frame every twelve frames at most */ |
|
244 g_pVideo->pix_fmt = PIX_FMT_YUV420P; |
|
245 |
|
246 // set quality |
|
247 if (g_VQuality > 100) |
|
248 g_pVideo->bit_rate = g_VQuality; |
|
249 else |
|
250 { |
|
251 g_pVideo->flags |= CODEC_FLAG_QSCALE; |
|
252 g_pVideo->global_quality = g_VQuality*FF_QP2LAMBDA; |
|
253 } |
|
254 |
|
255 // some formats want stream headers to be separate |
|
256 if (g_pFormat->flags & AVFMT_GLOBALHEADER) |
|
257 g_pVideo->flags |= CODEC_FLAG_GLOBAL_HEADER; |
|
258 |
|
259 #if LIBAVCODEC_VERSION_MAJOR < 53 |
|
260 // for some versions of ffmpeg x264 options must be set explicitly |
|
261 if (strcmp(g_pVCodec->name, "libx264") == 0) |
|
262 { |
|
263 g_pVideo->coder_type = FF_CODER_TYPE_AC; |
|
264 g_pVideo->flags |= CODEC_FLAG_LOOP_FILTER; |
|
265 g_pVideo->crf = 23; |
|
266 g_pVideo->thread_count = 3; |
|
267 g_pVideo->me_cmp = FF_CMP_CHROMA; |
|
268 g_pVideo->partitions = X264_PART_I8X8 | X264_PART_I4X4 | X264_PART_P8X8 | X264_PART_B8X8; |
|
269 g_pVideo->me_method = ME_HEX; |
|
270 g_pVideo->me_subpel_quality = 7; |
|
271 g_pVideo->me_range = 16; |
|
272 g_pVideo->gop_size = 250; |
|
273 g_pVideo->keyint_min = 25; |
|
274 g_pVideo->scenechange_threshold = 40; |
|
275 g_pVideo->i_quant_factor = 0.71; |
|
276 g_pVideo->b_frame_strategy = 1; |
|
277 g_pVideo->qcompress = 0.6; |
|
278 g_pVideo->qmin = 10; |
|
279 g_pVideo->qmax = 51; |
|
280 g_pVideo->max_qdiff = 4; |
|
281 g_pVideo->max_b_frames = 3; |
|
282 g_pVideo->refs = 3; |
|
283 g_pVideo->directpred = 1; |
|
284 g_pVideo->trellis = 1; |
|
285 g_pVideo->flags2 = CODEC_FLAG2_BPYRAMID | CODEC_FLAG2_MIXED_REFS | CODEC_FLAG2_WPRED | CODEC_FLAG2_8X8DCT | CODEC_FLAG2_FASTPSKIP; |
|
286 g_pVideo->weighted_p_pred = 2; |
|
287 } |
|
288 #endif |
|
289 |
|
290 // open the codec |
|
291 #if LIBAVCODEC_VERSION_MAJOR >= 53 |
|
292 AVDictionary* pDict = NULL; |
|
293 if (strcmp(g_pVCodec->name, "libx264") == 0) |
|
294 av_dict_set(&pDict, "preset", "medium", 0); |
|
295 |
|
296 if (avcodec_open2(g_pVideo, g_pVCodec, &pDict) < 0) |
|
297 #else |
|
298 if (avcodec_open(g_pVideo, g_pVCodec) < 0) |
|
299 #endif |
|
300 FatalError("Could not open video codec %s", g_pVCodec->long_name); |
|
301 |
|
302 g_pVFrame = avcodec_alloc_frame(); |
|
303 if (!g_pVFrame) |
|
304 FatalError("Could not allocate frame"); |
|
305 |
|
306 g_pVFrame->linesize[0] = g_Width; |
|
307 g_pVFrame->linesize[1] = g_Width/2; |
|
308 g_pVFrame->linesize[2] = g_Width/2; |
|
309 g_pVFrame->linesize[3] = 0; |
|
310 } |
|
311 |
|
312 static int WriteFrame(AVFrame* pFrame) |
|
313 { |
|
314 double AudioTime, VideoTime; |
|
315 |
|
316 // write interleaved audio frame |
|
317 if (g_pAStream) |
|
318 { |
|
319 VideoTime = (double)g_pVStream->pts.val*g_pVStream->time_base.num/g_pVStream->time_base.den; |
|
320 do |
|
321 AudioTime = (double)g_pAStream->pts.val*g_pAStream->time_base.num/g_pAStream->time_base.den; |
|
322 while (AudioTime < VideoTime && WriteAudioFrame()); |
|
323 } |
|
324 |
|
325 if (!g_pVStream) |
|
326 return 0; |
|
327 |
|
328 AVPacket Packet; |
|
329 av_init_packet(&Packet); |
|
330 Packet.data = NULL; |
|
331 Packet.size = 0; |
|
332 |
|
333 g_pVFrame->pts++; |
|
334 if (g_pFormat->flags & AVFMT_RAWPICTURE) |
|
335 { |
|
336 /* raw video case. The API will change slightly in the near |
|
337 future for that. */ |
|
338 Packet.flags |= AV_PKT_FLAG_KEY; |
|
339 Packet.stream_index = g_pVStream->index; |
|
340 Packet.data = (uint8_t*)pFrame; |
|
341 Packet.size = sizeof(AVPicture); |
|
342 |
|
343 if (av_interleaved_write_frame(g_pContainer, &Packet) != 0) |
|
344 FatalError("Error while writing video frame"); |
|
345 return 0; |
|
346 } |
|
347 else |
|
348 { |
|
349 #if LIBAVCODEC_VERSION_MAJOR >= 54 |
|
350 int got_packet; |
|
351 if (avcodec_encode_video2(g_pVideo, &Packet, pFrame, &got_packet) < 0) |
|
352 FatalError("avcodec_encode_video2 failed"); |
|
353 if (!got_packet) |
|
354 return 0; |
|
355 |
|
356 if (Packet.pts != AV_NOPTS_VALUE) |
|
357 Packet.pts = av_rescale_q(Packet.pts, g_pVideo->time_base, g_pVStream->time_base); |
|
358 if (Packet.dts != AV_NOPTS_VALUE) |
|
359 Packet.dts = av_rescale_q(Packet.dts, g_pVideo->time_base, g_pVStream->time_base); |
|
360 #else |
|
361 Packet.size = avcodec_encode_video(g_pVideo, g_OutBuffer, OUTBUFFER_SIZE, pFrame); |
|
362 if (Packet.size < 0) |
|
363 FatalError("avcodec_encode_video failed"); |
|
364 if (Packet.size == 0) |
|
365 return 0; |
|
366 |
|
367 if( g_pVideo->coded_frame->pts != AV_NOPTS_VALUE) |
|
368 Packet.pts = av_rescale_q(g_pVideo->coded_frame->pts, g_pVideo->time_base, g_pVStream->time_base); |
|
369 if( g_pVideo->coded_frame->key_frame ) |
|
370 Packet.flags |= AV_PKT_FLAG_KEY; |
|
371 Packet.data = g_OutBuffer; |
|
372 #endif |
|
373 // write the compressed frame in the media file |
|
374 Packet.stream_index = g_pVStream->index; |
|
375 if (av_interleaved_write_frame(g_pContainer, &Packet) != 0) |
|
376 FatalError("Error while writing video frame"); |
|
377 |
|
378 return 1; |
|
379 } |
|
380 } |
|
381 |
|
382 AVWRAP_DECL void AVWrapper_WriteFrame(uint8_t* pY, uint8_t* pCb, uint8_t* pCr) |
|
383 { |
|
384 g_pVFrame->data[0] = pY; |
|
385 g_pVFrame->data[1] = pCb; |
|
386 g_pVFrame->data[2] = pCr; |
|
387 WriteFrame(g_pVFrame); |
|
388 } |
|
389 |
|
390 AVWRAP_DECL void AVWrapper_Init( |
|
391 void (*pAddFileLogRaw)(const char*), |
|
392 const char* pFilename, |
|
393 const char* pDesc, |
|
394 const char* pSoundFile, |
|
395 const char* pFormatName, |
|
396 const char* pVCodecName, |
|
397 const char* pACodecName, |
|
398 int Width, int Height, |
|
399 int FramerateNum, int FramerateDen, |
|
400 int VQuality) |
|
401 { |
|
402 AddFileLogRaw = pAddFileLogRaw; |
|
403 av_log_set_callback( &LogCallback ); |
|
404 |
|
405 g_Width = Width; |
|
406 g_Height = Height; |
|
407 g_Framerate.num = FramerateNum; |
|
408 g_Framerate.den = FramerateDen; |
|
409 g_VQuality = VQuality; |
|
410 |
|
411 // initialize libav and register all codecs and formats |
|
412 av_register_all(); |
|
413 |
|
414 // find format |
|
415 g_pFormat = av_guess_format(pFormatName, NULL, NULL); |
|
416 if (!g_pFormat) |
|
417 FatalError("Format \"%s\" was not found", pFormatName); |
|
418 |
|
419 // allocate the output media context |
|
420 g_pContainer = avformat_alloc_context(); |
|
421 if (!g_pContainer) |
|
422 FatalError("Could not allocate output context"); |
|
423 |
|
424 g_pContainer->oformat = g_pFormat; |
|
425 |
|
426 // store description of file |
|
427 av_dict_set(&g_pContainer->metadata, "comment", pDesc, 0); |
|
428 |
|
429 // append extesnion to filename |
|
430 char ext[16]; |
|
431 strncpy(ext, g_pFormat->extensions, 16); |
|
432 ext[15] = 0; |
|
433 ext[strcspn(ext,",")] = 0; |
|
434 snprintf(g_pContainer->filename, sizeof(g_pContainer->filename), "%s.%s", pFilename, ext); |
|
435 |
|
436 // find codecs |
|
437 g_pVCodec = avcodec_find_encoder_by_name(pVCodecName); |
|
438 g_pACodec = avcodec_find_encoder_by_name(pACodecName); |
|
439 |
|
440 // add audio and video stream to container |
|
441 g_pVStream = NULL; |
|
442 g_pAStream = NULL; |
|
443 |
|
444 if (g_pVCodec) |
|
445 AddVideoStream(); |
|
446 else |
|
447 Log("Video codec \"%s\" was not found; video will be ignored.\n", pVCodecName); |
|
448 |
|
449 if (g_pACodec) |
|
450 { |
|
451 g_pSoundFile = fopen(pSoundFile, "rb"); |
|
452 if (g_pSoundFile) |
|
453 { |
|
454 fread(&g_Frequency, 4, 1, g_pSoundFile); |
|
455 fread(&g_Channels, 4, 1, g_pSoundFile); |
|
456 AddAudioStream(); |
|
457 } |
|
458 else |
|
459 Log("Could not open %s\n", pSoundFile); |
|
460 } |
|
461 else |
|
462 Log("Audio codec \"%s\" was not found; audio will be ignored.\n", pACodecName); |
|
463 |
|
464 if (!g_pAStream && !g_pVStream) |
|
465 FatalError("No video, no audio, aborting..."); |
|
466 |
|
467 // write format info to log |
|
468 av_dump_format(g_pContainer, 0, g_pContainer->filename, 1); |
|
469 |
|
470 // open the output file, if needed |
|
471 if (!(g_pFormat->flags & AVFMT_NOFILE)) |
|
472 { |
|
473 if (avio_open(&g_pContainer->pb, g_pContainer->filename, AVIO_FLAG_WRITE) < 0) |
|
474 FatalError("Could not open output file (%s)", g_pContainer->filename); |
|
475 } |
|
476 |
|
477 // write the stream header, if any |
|
478 avformat_write_header(g_pContainer, NULL); |
|
479 |
|
480 g_pVFrame->pts = -1; |
|
481 } |
|
482 |
|
483 AVWRAP_DECL void AVWrapper_Close() |
|
484 { |
|
485 // output buffered frames |
|
486 if (g_pVCodec->capabilities & CODEC_CAP_DELAY) |
|
487 while( WriteFrame(NULL) ); |
|
488 // output any remaining audio |
|
489 while( WriteAudioFrame() ); |
|
490 |
|
491 // write the trailer, if any. |
|
492 av_write_trailer(g_pContainer); |
|
493 |
|
494 // close the output file |
|
495 if (!(g_pFormat->flags & AVFMT_NOFILE)) |
|
496 avio_close(g_pContainer->pb); |
|
497 |
|
498 // free everything |
|
499 if (g_pVStream) |
|
500 { |
|
501 avcodec_close(g_pVideo); |
|
502 av_free(g_pVideo); |
|
503 av_free(g_pVStream); |
|
504 av_free(g_pVFrame); |
|
505 } |
|
506 if (g_pAStream) |
|
507 { |
|
508 avcodec_close(g_pAudio); |
|
509 av_free(g_pAudio); |
|
510 av_free(g_pAStream); |
|
511 av_free(g_pAFrame); |
|
512 av_free(g_pSamples); |
|
513 fclose(g_pSoundFile); |
|
514 } |
|
515 |
|
516 av_free(g_pContainer); |
|
517 } |
|