Merge pull request #113 from tesselode/fix-multi-targets
[wdl/wdl-ol.git] / WDL / ffmpeg.h
blob9bd623c849f8e902531fd92d047c83f328104b4a
1 /*
2 WDL - ffmpeg.h
3 Copyright (C) 2005 Cockos Incorporated
4 Copyright (C) 1999-2004 Nullsoft, Inc.
6 This software is provided 'as-is', without any express or implied
7 warranty. In no event will the authors be held liable for any damages
8 arising from the use of this software.
10 Permission is granted to anyone to use this software for any purpose,
11 including commercial applications, and to alter it and redistribute it
12 freely, subject to the following restrictions:
14 1. The origin of this software must not be misrepresented; you must not
15 claim that you wrote the original software. If you use this software
16 in a product, an acknowledgment in the product documentation would be
17 appreciated but is not required.
18 2. Altered source versions must be plainly marked as such, and must not be
19 misrepresented as being the original software.
20 3. This notice may not be removed or altered from any source distribution.
24 #ifndef _WDL_FFMPEG_H
25 #define _WDL_FFMPEG_H
27 #ifdef _MSC_VER
28 #include "../sdks/ffmpeg/include/stdint.h"
29 #include "../sdks/ffmpeg/include/inttypes.h"
30 #endif
32 extern "C"
34 #include "../sdks/ffmpeg/include/libavformat/avformat.h"
35 #include "../sdks/ffmpeg/include/libswscale/swscale.h"
38 #include "queue.h"
40 #ifndef INT64_C
41 #define INT64_C(val) val##i64
42 #endif
44 #ifndef INT64_MIN
45 #ifdef _MSC_VER
46 #define INT64_MIN (-0x7fffffffffffffff##i64 - 1)
47 #else
48 #define INT64_MIN (-0x7fffffffffffffffLL - 1)
49 #endif
50 #endif
52 #ifndef INT64_MAX
53 #define INT64_MAX INT64_C(9223372036854775807)
54 #endif
56 class WDL_VideoEncode
58 public:
59 //bitrates are in kbps
60 WDL_VideoEncode(const char *format, int width, int height, double fps, int bitrate, const char *audioformat=NULL, int asr=44100, int ach=2, int abitrate=0)
62 m_init = 0;
63 m_img_resample_ctx = NULL;
64 m_stream = NULL;
65 m_astream = NULL;
66 m_video_enc = NULL;
67 m_audio_enc = NULL;
68 m_bit_buffer = NULL;
69 avcodec_get_frame_defaults(&m_cvtpic);
71 //initialize FFMpeg
73 static int init = 0;
74 if(!init) av_register_all();
75 init = 1;
78 m_ctx = av_alloc_format_context();
79 AVOutputFormat *fmt = guess_format(format, NULL, NULL);
80 if(!m_ctx || !fmt) return;
82 m_ctx->oformat = fmt;
84 m_stream = av_new_stream(m_ctx, m_ctx->nb_streams);
85 if(!m_stream) return;
87 //init video
88 avcodec_get_context_defaults2(m_stream->codec, CODEC_TYPE_VIDEO);
89 m_video_enc = m_stream->codec;
91 CodecID codec_id = av_guess_codec(m_ctx->oformat, NULL, NULL, NULL, CODEC_TYPE_VIDEO);
92 m_video_enc->codec_id = codec_id;
94 AVCodec *codec;
95 codec = avcodec_find_encoder(codec_id);
96 if (!codec) return;
98 m_video_enc->width = width;
99 m_video_enc->height = height;
100 m_video_enc->time_base.den = fps * 10000;
101 m_video_enc->time_base.num = 10000;
103 m_video_enc->pix_fmt = PIX_FMT_BGRA;
104 if (codec && codec->pix_fmts)
106 const enum PixelFormat *p= codec->pix_fmts;
107 for (; *p!=-1; p++) {
108 if (*p == m_video_enc->pix_fmt)
109 break;
111 if (*p == -1)
112 m_video_enc->pix_fmt = codec->pix_fmts[0];
115 if(m_video_enc->pix_fmt != PIX_FMT_BGRA)
117 //this codec needs colorplane conversion
118 int sws_flags = SWS_BICUBIC;
119 m_img_resample_ctx = sws_getContext(
120 width,
121 height,
122 PIX_FMT_BGRA,
123 width,
124 height,
125 m_video_enc->pix_fmt,
126 sws_flags, NULL, NULL, NULL);
128 if ( avpicture_alloc( (AVPicture*)&m_cvtpic, m_video_enc->pix_fmt,
129 m_video_enc->width, m_video_enc->height) )
130 return;
133 m_video_enc->bit_rate = bitrate*1024;
134 m_video_enc->gop_size = 12; /* emit one intra frame every twelve frames at most */
136 // some formats want stream headers to be separate
137 if(m_ctx->oformat->flags & AVFMT_GLOBALHEADER)
138 m_video_enc->flags |= CODEC_FLAG_GLOBAL_HEADER;
140 m_video_enc->max_qdiff = 3; // set the default maximum quantizer difference between frames
141 m_video_enc->thread_count = 1; // set how many thread need be used in encoding
142 m_video_enc->rc_override_count = 0; // set ratecontrol override to 0
143 if (!m_video_enc->rc_initial_buffer_occupancy)
145 m_video_enc->rc_initial_buffer_occupancy = m_video_enc->rc_buffer_size*3/4; // set decoder buffer size
147 m_video_enc->me_threshold = 0; // set motion estimation threshold value to 0
148 m_video_enc->intra_dc_precision = 0;
149 m_video_enc->strict_std_compliance = 0;
150 m_ctx->preload = (int)(0.5 * AV_TIME_BASE);
151 m_ctx->max_delay = (int)(0.7 * AV_TIME_BASE);
152 m_ctx->loop_output = -1;
154 m_ctx->timestamp = 0;
156 av_log_set_callback(ffmpeg_avcodec_log);
157 av_log_set_level(AV_LOG_ERROR);
159 if (avcodec_open(m_video_enc, codec) < 0)
161 return;
164 //init audio
165 if(abitrate)
167 m_astream = av_new_stream(m_ctx, m_ctx->nb_streams);
168 if(!m_astream) return;
170 avcodec_get_context_defaults2(m_astream->codec, CODEC_TYPE_AUDIO);
171 m_audio_enc = m_astream->codec;
173 //use the format's default audio codec
174 CodecID codeca_id = av_guess_codec(m_ctx->oformat, audioformat, NULL, NULL, CODEC_TYPE_AUDIO);
175 m_audio_enc->codec_id = codeca_id;
177 AVCodec *acodec;
178 acodec = avcodec_find_encoder(codeca_id);
179 if (!acodec) return;
181 m_audio_enc->bit_rate = abitrate*1024;
182 m_audio_enc->sample_rate = asr;
183 m_audio_enc->channels = ach;
185 if (avcodec_open(m_audio_enc, acodec) < 0) return;
188 AVFormatParameters params, *ap = &params;
189 memset(ap, 0, sizeof(*ap));
190 if (av_set_parameters(m_ctx, ap) < 0) return;
192 url_open_dyn_buf(&m_ctx->pb);
193 av_write_header(m_ctx);
195 int size = width * height;
196 m_bit_buffer_size = 1024 * 256;
197 m_bit_buffer_size= FFMAX(m_bit_buffer_size, 4*size);
199 m_bit_buffer = (uint8_t*)av_malloc(m_bit_buffer_size);
201 m_init = 1;
203 ~WDL_VideoEncode()
205 if(m_stream && m_stream->codec) avcodec_close(m_stream->codec);
206 if(m_astream && m_astream->codec) avcodec_close(m_astream->codec);
207 av_free(m_bit_buffer);
208 av_free(m_cvtpic.data[0]);
209 av_free(m_ctx);
212 int isInited() { return m_init; }
214 void encodeVideo(const LICE_pixel *buf)
216 if(m_img_resample_ctx)
218 //convert to output format
219 uint8_t *p[1]={(uint8_t*)buf};
220 int w[1]={m_video_enc->width*4};
221 sws_scale(m_img_resample_ctx, p, w,
222 0, m_video_enc->height, m_cvtpic.data, m_cvtpic.linesize);
224 int ret = avcodec_encode_video(m_video_enc, m_bit_buffer, m_bit_buffer_size, &m_cvtpic);
225 if(ret>0)
227 AVPacket pkt;
228 av_init_packet(&pkt);
229 pkt.stream_index = 0;
230 pkt.data = m_bit_buffer;
231 pkt.size = ret;
232 if (m_video_enc->coded_frame->pts != AV_NOPTS_VALUE)
233 pkt.pts= av_rescale_q(m_video_enc->coded_frame->pts, m_video_enc->time_base, m_stream->time_base);
234 if(m_video_enc->coded_frame->key_frame)
235 pkt.flags |= PKT_FLAG_KEY;
236 av_interleaved_write_frame(m_ctx, &pkt);
240 void encodeAudio(short *data, int nbsamples)
242 AVPacket pkt;
243 int l = nbsamples;
244 int fs = m_audio_enc->frame_size*m_audio_enc->channels;
245 while(l>=fs)
247 av_init_packet(&pkt);
248 pkt.size= avcodec_encode_audio(m_audio_enc, m_bit_buffer, m_bit_buffer_size, data);
249 if (m_audio_enc->coded_frame->pts != AV_NOPTS_VALUE)
250 pkt.pts= av_rescale_q(m_audio_enc->coded_frame->pts, m_audio_enc->time_base, m_astream->time_base);
251 pkt.flags |= PKT_FLAG_KEY;
252 pkt.stream_index = 1;
253 pkt.data = m_bit_buffer;
254 av_interleaved_write_frame(m_ctx, &pkt);
256 data += fs;
257 l -= fs;
261 int getBytes(unsigned char *p, int size)
263 //looks like there's no other way to get data from ffmpeg's dynamic buffers apart from closing them
264 if (m_queue.GetSize() < size && m_init)
266 uint8_t *pb_buffer;
267 int l = url_close_dyn_buf(m_ctx-> pb, &pb_buffer);
268 if(l > 0)
270 m_queue.Add(pb_buffer, l);
271 av_free(pb_buffer);
273 url_open_dyn_buf(&m_ctx->pb); //sets up next dynamic buffer for ffmpeg
276 int s = wdl_min(size, m_queue.GetSize());
277 if(s)
279 memcpy(p, m_queue.Get(), s);
280 m_queue.Advance(s);
281 m_queue.Compact();
283 return s;
286 void close()
288 av_write_trailer(m_ctx);
289 uint8_t *pb_buffer;
290 int l = url_close_dyn_buf(m_ctx-> pb, &pb_buffer);
291 if(l)
293 m_queue.Add(pb_buffer, l);
294 av_free(pb_buffer);
296 m_init=0;
299 //useful to get debugging information from ffmpeg
300 static void ffmpeg_avcodec_log(void *ptr, int val, const char * msg, va_list ap)
302 AVClass* avc= ptr ? *(AVClass**)ptr : NULL;
303 vprintf(msg, ap);
306 protected:
307 int m_init;
309 AVFormatContext *m_ctx;
310 AVStream *m_stream, *m_astream;
311 AVCodecContext *m_video_enc, *m_audio_enc;
312 struct SwsContext *m_img_resample_ctx;
313 AVFrame m_cvtpic;
314 uint8_t *m_bit_buffer;
315 int m_bit_buffer_size;
317 WDL_Queue m_queue;
320 class WDL_VideoDecode
322 public:
323 WDL_VideoDecode(const char *fn)
325 m_inited = 0;
326 m_ctx = NULL;
327 m_frame = NULL;
328 m_ic = NULL;
329 m_sws = NULL;
330 m_sws_destw=0;
331 m_sws_desth=0;
332 m_curtime=-1.0;
334 //initialize FFMpeg
336 static int init = 0;
337 if(!init) av_register_all();
338 init = 1;
341 int ret = av_open_input_file(&m_ic, fn, NULL, 0, NULL);
342 if (ret < 0) return;
344 ret = av_find_stream_info(m_ic);
345 if (ret < 0) return;
347 // find the stream that corresponds to the stream type
348 int i, stream = -1;
349 for(i=0; i < (int)m_ic->nb_streams; i++)
351 int st = m_ic->streams[i]->codec->codec_type;
352 if(st==CODEC_TYPE_VIDEO)
354 stream = i;
355 break;
358 if(stream==-1) return; //no stream found
360 m_ctx = m_ic->streams[stream]->codec;
362 AVCodec *pCodec = avcodec_find_decoder(m_ctx->codec_id);
363 if(pCodec == NULL) return; // codec not found
365 if(avcodec_open(m_ctx, pCodec)<0) return; // Could not open codec
367 AVStream *st = m_ic->streams[stream];
368 if(st->r_frame_rate.den && st->r_frame_rate.num)
369 m_fps = av_q2d(st->r_frame_rate);
370 else
371 m_fps = 1/av_q2d(st->codec->time_base);
373 m_frame = avcodec_alloc_frame();
375 m_w = m_ctx->width;
376 m_h = m_ctx->height;
378 m_pixfmt=st->codec->pix_fmt;
380 if(m_ic->duration == AV_NOPTS_VALUE)
382 //FFmpeg can't get the duration
383 //approximate the duration of the file with the first packets bitrates
384 AVStream *st = m_ic->streams[stream];
385 int bitrate = 0;
386 for(i=0; i < (int)m_ic->nb_streams; i++)
388 bitrate += m_ic->streams[i]->codec->bit_rate;
390 bitrate /= 8;
391 if(bitrate)
392 m_len = (double)m_ic->file_size/bitrate;
393 else
394 m_len = 30; //last resort
396 else
397 m_len = (double)m_ic->duration/AV_TIME_BASE;
398 m_stream = stream;
400 m_inited = 1;
402 ~WDL_VideoDecode()
404 if(m_frame) av_free(m_frame);
405 if(m_ic) av_close_input_file(m_ic);
406 if(m_sws) sws_freeContext(m_sws);
408 int isInited() { return m_inited; }
409 int GetVideoFrameAtTime(LICE_IBitmap *dst, double atTime, double *startTime, double *endTime, bool resizeToBuf)
411 if(!m_inited) return 0;
412 if(m_curtime == -1.0 || atTime<m_curtime || (atTime-m_curtime)>(1.0/m_fps))
414 if(avformat_seek_file(m_ic, -1, INT64_MIN, atTime*AV_TIME_BASE, INT64_MAX, AVSEEK_FLAG_BACKWARD) < 0)
416 //fallback to old seeking API
417 av_seek_frame(m_ic, -1, atTime*AV_TIME_BASE, AVSEEK_FLAG_BACKWARD);
419 avcodec_flush_buffers(m_ctx);
422 double startpts = -1;
423 while(1)
425 AVPacket packet;
426 if(av_read_frame(m_ic, &packet)<0) return 0; //end of file
427 if(packet.stream_index==m_stream)
429 double packetpts = getPresentationTime(&packet);
430 if(startpts == -1) startpts = packetpts;
432 int frameFinished = 0;
433 int l = avcodec_decode_video(m_ctx, m_frame, &frameFinished, packet.data, packet.size);
434 if(l>=0)
436 // Did we get a video frame?
437 if(frameFinished)
439 double pts = startpts;
440 double epts = packetpts+(1.0/m_fps);
442 if(epts<atTime)
444 //keep decoding until we get to the desired seek frame
445 startpts = packetpts;
446 continue;
449 if(startTime) *startTime = pts;
450 if(endTime) *endTime = epts;
451 m_curtime = epts;
453 //convert decoded image to correct format
454 int w = m_w;
455 int h = m_h;
456 if(resizeToBuf)
458 w = dst->getWidth();
459 h = dst->getHeight();
461 else
463 dst->resize(w, h);
465 unsigned int *bits = dst->getBits();
466 /*#ifdef _WIN32
467 uint8_t *dstd[4]= {(uint8_t *)bits+(dst->getRowSpan()*4*(h-1)),};
468 int dst_stride[4]={-dst->getRowSpan()*4,};
469 #else*/
470 uint8_t *dstd[4]= {(uint8_t *)bits,};
471 int dst_stride[4]={dst->getRowSpan()*4,};
472 //#endif
474 if (!m_sws || m_sws_desth != h || m_sws_destw != w)
476 int sws_flags = SWS_BICUBIC;
477 PixelFormat pfout =
478 #ifdef _WIN32
479 PIX_FMT_RGB32;
480 #else
481 PIX_FMT_BGR32_1;
482 #endif
483 if(m_sws) sws_freeContext(m_sws);
484 m_sws = sws_getContext(m_w, m_h, m_pixfmt, w, h, pfout, sws_flags, NULL, NULL, NULL);
485 m_sws_desth = h;
486 m_sws_destw = w;
489 if (m_sws)
490 sws_scale(m_sws, m_frame->data, m_frame->linesize, 0, m_h, dstd, dst_stride);
492 av_free_packet(&packet);
493 return 1;
497 av_free_packet(&packet);
501 return 0;
504 protected:
506 double getPresentationTime(AVPacket *packet)
508 double mpts = 0;
509 if(packet->dts != AV_NOPTS_VALUE) mpts = (double)packet->dts;
510 mpts *= av_q2d(m_ic->streams[packet->stream_index]->time_base);
511 mpts -= (double)m_ic->start_time/AV_TIME_BASE;
512 return mpts;
515 int m_inited;
517 AVFormatContext *m_ic;
518 AVCodecContext *m_ctx;
520 AVFrame *m_frame;
522 int m_stream;
524 int m_w, m_h, m_format;
525 double m_fps, m_len;
526 struct SwsContext *m_sws;
527 int m_sws_desth, m_sws_destw;
528 PixelFormat m_pixfmt;
530 double m_curtime;
533 #endif