19 #include <stdlib.h> |
19 #include <stdlib.h> |
20 #include <stdio.h> |
20 #include <stdio.h> |
21 #include <stdint.h> |
21 #include <stdint.h> |
22 #include <string.h> |
22 #include <string.h> |
23 #include <stdarg.h> |
23 #include <stdarg.h> |
|
24 |
|
25 #include "libavcodec/avcodec.h" |
24 #include "libavformat/avformat.h" |
26 #include "libavformat/avformat.h" |
|
27 #include "libavutil/avutil.h" |
25 #include "libavutil/mathematics.h" |
28 #include "libavutil/mathematics.h" |
26 |
|
27 #ifndef AVIO_FLAG_WRITE |
|
28 #define AVIO_FLAG_WRITE AVIO_WRONLY |
|
29 #endif |
|
30 |
29 |
31 #if (defined _MSC_VER) |
30 #if (defined _MSC_VER) |
32 #define AVWRAP_DECL __declspec(dllexport) |
31 #define AVWRAP_DECL __declspec(dllexport) |
33 #elif ((__GNUC__ >= 3) && (!__EMX__) && (!sun)) |
32 #elif ((__GNUC__ >= 3) && (!__EMX__) && (!sun)) |
34 #define AVWRAP_DECL __attribute__((visibility("default"))) |
33 #define AVWRAP_DECL __attribute__((visibility("default"))) |
55 static FILE* g_pSoundFile; |
54 static FILE* g_pSoundFile; |
56 static int16_t* g_pSamples; |
55 static int16_t* g_pSamples; |
57 static int g_NumSamples; |
56 static int g_NumSamples; |
58 |
57 |
59 |
58 |
|
59 // compatibility section |
60 #if LIBAVCODEC_VERSION_MAJOR < 54 |
60 #if LIBAVCODEC_VERSION_MAJOR < 54 |
61 #define OUTBUFFER_SIZE 200000 |
61 #define OUTBUFFER_SIZE 200000 |
62 static uint8_t g_OutBuffer[OUTBUFFER_SIZE]; |
62 static uint8_t g_OutBuffer[OUTBUFFER_SIZE]; |
63 #endif |
63 #define avcodec_open2(x, y, z) avcodec_open(x, y) |
|
64 #endif |
|
65 |
|
66 #if LIBAVCODEC_VERSION_MAJOR < 56 |
|
67 #define av_frame_alloc avcodec_alloc_frame |
|
68 #define av_frame_free av_freep |
|
69 #endif |
|
70 |
|
71 #if LIBAVCODEC_VERSION_MAJOR < 57 |
|
72 #define AV_CODEC_CAP_DELAY CODEC_CAP_DELAY |
|
73 #define AV_CODEC_CAP_VARIABLE_FRAME_SIZE CODEC_CAP_VARIABLE_FRAME_SIZE |
|
74 #define AV_CODEC_FLAG_GLOBAL_HEADER CODEC_FLAG_GLOBAL_HEADER |
|
75 #define AV_CODEC_FLAG_QSCALE CODEC_FLAG_QSCALE |
|
76 #endif |
|
77 |
|
78 #if LIBAVFORMAT_VERSION_MAJOR < 53 |
|
79 #define AVIO_FLAG_WRITE AVIO_WRONLY |
|
80 #endif |
|
81 |
|
82 #if LIBAVFORMAT_VERSION_MAJOR < 54 |
|
83 #define avformat_new_stream(x, y) av_new_stream(x, y->type == AVMEDIA_TYPE_AUDIO) |
|
84 #endif |
|
85 |
|
86 #if LIBAVUTIL_VERSION_MAJOR < 54 |
|
87 #define AV_PIX_FMT_YUV420P PIX_FMT_YUV420P |
|
88 #endif |
|
89 |
64 |
90 |
65 // pointer to function from hwengine (uUtils.pas) |
91 // pointer to function from hwengine (uUtils.pas) |
66 static void (*AddFileLogRaw)(const char* pString); |
92 static void (*AddFileLogRaw)(const char* pString); |
67 |
93 |
68 static int FatalError(const char* pFmt, ...) |
94 static int FatalError(const char* pFmt, ...) |
103 AddFileLogRaw(Buffer); |
129 AddFileLogRaw(Buffer); |
104 } |
130 } |
105 |
131 |
106 static void AddAudioStream() |
132 static void AddAudioStream() |
107 { |
133 { |
108 #if LIBAVFORMAT_VERSION_MAJOR >= 53 |
|
109 g_pAStream = avformat_new_stream(g_pContainer, g_pACodec); |
134 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) |
135 if(!g_pAStream) |
114 { |
136 { |
115 Log("Could not allocate audio stream\n"); |
137 Log("Could not allocate audio stream\n"); |
116 return; |
138 return; |
117 } |
139 } |
129 |
151 |
130 // set quality |
152 // set quality |
131 g_pAudio->bit_rate = 160000; |
153 g_pAudio->bit_rate = 160000; |
132 |
154 |
133 // for codecs that support variable bitrate use it, it should be better |
155 // for codecs that support variable bitrate use it, it should be better |
134 g_pAudio->flags |= CODEC_FLAG_QSCALE; |
156 g_pAudio->flags |= AV_CODEC_FLAG_QSCALE; |
135 g_pAudio->global_quality = 1*FF_QP2LAMBDA; |
157 g_pAudio->global_quality = 1*FF_QP2LAMBDA; |
136 |
158 |
137 // some formats want stream headers to be separate |
159 // some formats want stream headers to be separate |
138 if (g_pFormat->flags & AVFMT_GLOBALHEADER) |
160 if (g_pFormat->flags & AVFMT_GLOBALHEADER) |
139 g_pAudio->flags |= CODEC_FLAG_GLOBAL_HEADER; |
161 g_pAudio->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; |
140 |
162 |
141 // open it |
163 // open it |
142 #if LIBAVCODEC_VERSION_MAJOR >= 53 |
|
143 if (avcodec_open2(g_pAudio, g_pACodec, NULL) < 0) |
164 if (avcodec_open2(g_pAudio, g_pACodec, NULL) < 0) |
144 #else |
|
145 if (avcodec_open(g_pAudio, g_pACodec) < 0) |
|
146 #endif |
|
147 { |
165 { |
148 Log("Could not open audio codec %s\n", g_pACodec->long_name); |
166 Log("Could not open audio codec %s\n", g_pACodec->long_name); |
149 return; |
167 return; |
150 } |
168 } |
151 |
169 |
152 #if LIBAVCODEC_VERSION_MAJOR >= 54 |
170 #if LIBAVCODEC_VERSION_MAJOR >= 54 |
153 if (g_pACodec->capabilities & CODEC_CAP_VARIABLE_FRAME_SIZE) |
171 if (g_pACodec->capabilities & AV_CODEC_CAP_VARIABLE_FRAME_SIZE) |
154 #else |
172 #else |
155 if (g_pAudio->frame_size == 0) |
173 if (g_pAudio->frame_size == 0) |
156 #endif |
174 #endif |
157 g_NumSamples = 4096; |
175 g_NumSamples = 4096; |
158 else |
176 else |
159 g_NumSamples = g_pAudio->frame_size; |
177 g_NumSamples = g_pAudio->frame_size; |
160 g_pSamples = (int16_t*)av_malloc(g_NumSamples*g_Channels*sizeof(int16_t)); |
178 g_pSamples = (int16_t*)av_malloc(g_NumSamples*g_Channels*sizeof(int16_t)); |
161 g_pAFrame = avcodec_alloc_frame(); |
179 g_pAFrame = av_frame_alloc(); |
162 if (!g_pAFrame) |
180 if (!g_pAFrame) |
163 { |
181 { |
164 Log("Could not allocate frame\n"); |
182 Log("Could not allocate frame\n"); |
165 return; |
183 return; |
166 } |
184 } |
170 static int WriteAudioFrame() |
188 static int WriteAudioFrame() |
171 { |
189 { |
172 if (!g_pAStream) |
190 if (!g_pAStream) |
173 return 0; |
191 return 0; |
174 |
192 |
175 AVPacket Packet = { 0 }; |
193 AVPacket Packet; |
176 av_init_packet(&Packet); |
194 av_init_packet(&Packet); |
177 |
195 |
178 int NumSamples = fread(g_pSamples, 2*g_Channels, g_NumSamples, g_pSoundFile); |
196 int NumSamples = fread(g_pSamples, 2*g_Channels, g_NumSamples, g_pSoundFile); |
179 |
197 |
180 #if LIBAVCODEC_VERSION_MAJOR >= 53 |
198 #if LIBAVCODEC_VERSION_MAJOR >= 53 |
215 } |
233 } |
216 |
234 |
217 // add a video output stream |
235 // add a video output stream |
218 static int AddVideoStream() |
236 static int AddVideoStream() |
219 { |
237 { |
220 #if LIBAVFORMAT_VERSION_MAJOR >= 53 |
|
221 g_pVStream = avformat_new_stream(g_pContainer, g_pVCodec); |
238 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) |
239 if (!g_pVStream) |
226 return FatalError("Could not allocate video stream"); |
240 return FatalError("Could not allocate video stream"); |
227 |
241 |
228 g_pVideo = g_pVStream->codec; |
242 g_pVideo = g_pVStream->codec; |
229 |
243 |
239 timebase should be 1/framerate and timestamp increments should be |
253 timebase should be 1/framerate and timestamp increments should be |
240 identically 1. */ |
254 identically 1. */ |
241 g_pVideo->time_base.den = g_Framerate.num; |
255 g_pVideo->time_base.den = g_Framerate.num; |
242 g_pVideo->time_base.num = g_Framerate.den; |
256 g_pVideo->time_base.num = g_Framerate.den; |
243 //g_pVideo->gop_size = 12; /* emit one intra frame every twelve frames at most */ |
257 //g_pVideo->gop_size = 12; /* emit one intra frame every twelve frames at most */ |
244 g_pVideo->pix_fmt = PIX_FMT_YUV420P; |
258 g_pVideo->pix_fmt = AV_PIX_FMT_YUV420P; |
245 |
259 |
246 // set quality |
260 // set quality |
247 if (g_VQuality > 100) |
261 if (g_VQuality > 100) |
248 g_pVideo->bit_rate = g_VQuality; |
262 g_pVideo->bit_rate = g_VQuality; |
249 else |
263 else |
250 { |
264 { |
251 g_pVideo->flags |= CODEC_FLAG_QSCALE; |
265 g_pVideo->flags |= AV_CODEC_FLAG_QSCALE; |
252 g_pVideo->global_quality = g_VQuality*FF_QP2LAMBDA; |
266 g_pVideo->global_quality = g_VQuality*FF_QP2LAMBDA; |
253 } |
267 } |
254 |
268 |
255 // some formats want stream headers to be separate |
269 // some formats want stream headers to be separate |
256 if (g_pFormat->flags & AVFMT_GLOBALHEADER) |
270 if (g_pFormat->flags & AVFMT_GLOBALHEADER) |
257 g_pVideo->flags |= CODEC_FLAG_GLOBAL_HEADER; |
271 g_pVideo->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; |
258 |
272 |
259 #if LIBAVCODEC_VERSION_MAJOR < 53 |
273 #if LIBAVCODEC_VERSION_MAJOR < 53 |
260 // for some versions of ffmpeg x264 options must be set explicitly |
274 // for some versions of ffmpeg x264 options must be set explicitly |
261 if (strcmp(g_pVCodec->name, "libx264") == 0) |
275 if (strcmp(g_pVCodec->name, "libx264") == 0) |
262 { |
276 { |
290 // open the codec |
304 // open the codec |
291 #if LIBAVCODEC_VERSION_MAJOR >= 53 |
305 #if LIBAVCODEC_VERSION_MAJOR >= 53 |
292 AVDictionary* pDict = NULL; |
306 AVDictionary* pDict = NULL; |
293 if (strcmp(g_pVCodec->name, "libx264") == 0) |
307 if (strcmp(g_pVCodec->name, "libx264") == 0) |
294 av_dict_set(&pDict, "preset", "medium", 0); |
308 av_dict_set(&pDict, "preset", "medium", 0); |
|
309 #endif |
295 |
310 |
296 if (avcodec_open2(g_pVideo, g_pVCodec, &pDict) < 0) |
311 if (avcodec_open2(g_pVideo, g_pVCodec, &pDict) < 0) |
297 #else |
|
298 if (avcodec_open(g_pVideo, g_pVCodec) < 0) |
|
299 #endif |
|
300 return FatalError("Could not open video codec %s", g_pVCodec->long_name); |
312 return FatalError("Could not open video codec %s", g_pVCodec->long_name); |
301 |
313 |
302 g_pVFrame = avcodec_alloc_frame(); |
314 g_pVFrame = av_frame_alloc(); |
303 if (!g_pVFrame) |
315 if (!g_pVFrame) |
304 return FatalError("Could not allocate frame"); |
316 return FatalError("Could not allocate frame"); |
305 |
317 |
306 g_pVFrame->linesize[0] = g_Width; |
318 g_pVFrame->linesize[0] = g_Width; |
307 g_pVFrame->linesize[1] = g_Width/2; |
319 g_pVFrame->linesize[1] = g_Width/2; |
315 double AudioTime, VideoTime; |
327 double AudioTime, VideoTime; |
316 int ret; |
328 int ret; |
317 // write interleaved audio frame |
329 // write interleaved audio frame |
318 if (g_pAStream) |
330 if (g_pAStream) |
319 { |
331 { |
320 VideoTime = (double)g_pVStream->pts.val*g_pVStream->time_base.num/g_pVStream->time_base.den; |
332 VideoTime = (double)g_pVFrame->pts * g_pVStream->time_base.num/g_pVStream->time_base.den; |
321 do |
333 do |
322 { |
334 { |
323 AudioTime = (double)g_pAStream->pts.val*g_pAStream->time_base.num/g_pAStream->time_base.den; |
335 AudioTime = (double)g_pAFrame->pts * g_pAStream->time_base.num/g_pAStream->time_base.den; |
324 ret = WriteAudioFrame(); |
336 ret = WriteAudioFrame(); |
325 } |
337 } |
326 while (AudioTime < VideoTime && ret); |
338 while (AudioTime < VideoTime && ret); |
327 if (ret < 0) |
339 if (ret < 0) |
328 return ret; |
340 return ret; |