2009-12-03 Jeffrey Stedfast <fejj@novell.com>
[moon.git] / src / pipeline-ffmpeg.cpp
blobbd7d610624c0cb761d23963639a14fdd2e7f6fc1
1 /*
2 * pipeline-ffmpeg.cpp: Ffmpeg related parts of the pipeline for the media
4 * Contact:
5 * Moonlight List (moonlight-list@lists.ximian.com)
7 * Copyright 2007 Novell, Inc. (http://www.novell.com)
9 * See the LICENSE file included with the distribution for details.
14 * FFmpegDecoder
17 #include <config.h>
19 #include <stdlib.h>
20 #include <glib.h>
21 #include <unistd.h>
22 #include <stdlib.h>
23 #include <pthread.h>
25 #include "pipeline-ffmpeg.h"
26 #include "pipeline.h"
27 #include "mp3.h"
28 #include "clock.h"
29 #include "debug.h"
32 bool ffmpeg_initialized = false;
33 bool ffmpeg_registered = false;
35 pthread_mutex_t ffmpeg_mutex = PTHREAD_MUTEX_INITIALIZER;
37 void
38 initialize_ffmpeg ()
40 if (ffmpeg_initialized)
41 return;
43 avcodec_init ();
44 avcodec_register_all ();
46 ffmpeg_initialized = true;
49 void
50 register_ffmpeg ()
52 initialize_ffmpeg ();
54 Media::RegisterDecoder (new FfmpegDecoderInfo ());
55 //Media::RegisterDemuxer (new FfmpegDemuxerInfo ());
59 * FfmpegDecoder
62 FfmpegDecoder::FfmpegDecoder (Media* media, IMediaStream* stream)
63 : IMediaDecoder (Type::FFMPEGDECODER, media, stream),
64 audio_buffer (NULL), has_delayed_frame (false)
66 //printf ("FfmpegDecoder::FfmpegDecoder (%p, %p).\n", media, stream);
68 if (stream->min_padding < FF_INPUT_BUFFER_PADDING_SIZE)
69 stream->min_padding = FF_INPUT_BUFFER_PADDING_SIZE;
71 initialize_ffmpeg ();
73 frame_buffer = NULL;
74 frame_buffer_length = 0;
75 last_pts = G_MAXUINT64;
78 PixelFormat
79 FfmpegDecoder::ToFfmpegPixFmt (MoonPixelFormat format)
81 switch (format) {
82 case MoonPixelFormatYUV420P: return PIX_FMT_YUV420P;
83 case MoonPixelFormatRGB32: return PIX_FMT_RGB32;
84 default:
85 //printf ("FfmpegDecoder::ToFfmpegPixFmt (%i): Unknown pixel format.\n", format);
86 return PIX_FMT_NONE;
90 MoonPixelFormat
91 FfmpegDecoder::ToMoonPixFmt (PixelFormat format)
93 switch (format) {
94 case PIX_FMT_YUV420P: return MoonPixelFormatYUV420P;
95 case PIX_FMT_RGB32: return MoonPixelFormatRGB32;
96 default:
97 //printf ("FfmpegDecoder::ToMoonPixFmt (%i): Unknown pixel format.\n", format);
98 return MoonPixelFormatNone;
102 void
103 FfmpegDecoder::OpenDecoderAsyncInternal ()
105 MediaResult result;
107 result = Open ();
109 if (MEDIA_SUCCEEDED (result)) {
110 ReportOpenDecoderCompleted ();
111 } else {
112 ReportErrorOccurred (result);
116 MediaResult
117 FfmpegDecoder::Open ()
119 MediaResult result = MEDIA_SUCCESS;
120 IMediaStream *stream = GetStream ();
121 int ffmpeg_result = 0;
122 AVCodec *codec = NULL;
124 //printf ("FfmpegDecoder::Open ().\n");
126 pthread_mutex_lock (&ffmpeg_mutex);
128 codec = avcodec_find_decoder_by_name (stream->codec);
130 //printf ("FfmpegDecoder::Open (): Found codec: %p (id: '%s')\n", codec, stream->codec);
132 if (codec == NULL) {
133 result = MEDIA_UNKNOWN_CODEC;
134 Media::Warning (MEDIA_UNKNOWN_CODEC, "Unknown codec: %s", stream->codec);
135 goto failure;
138 context = avcodec_alloc_context ();
140 if (context == NULL) {
141 result = MEDIA_OUT_OF_MEMORY;
142 Media::Warning (MEDIA_OUT_OF_MEMORY, "Failed to allocate context.");
143 goto failure;
146 if (stream->extra_data_size > 0) {
147 //printf ("FfmpegDecoder::Open (): Found %i bytes of extra data.\n", stream->extra_data_size);
148 context->extradata_size = stream->extra_data_size;
149 context->extradata = (guint8*) av_mallocz (stream->extra_data_size + FF_INPUT_BUFFER_PADDING_SIZE + 100);
150 if (context->extradata == NULL) {
151 result = MEDIA_OUT_OF_MEMORY;
152 Media::Warning (MEDIA_OUT_OF_MEMORY, "Failed to allocate space for extra data.");
153 goto failure;
155 memcpy (context->extradata, stream->extra_data, stream->extra_data_size);
158 if (stream->GetType () == MediaTypeVideo) {
159 VideoStream *vs = (VideoStream*) stream;
160 context->width = vs->width;
161 context->height = vs->height;
162 #if LIBAVCODEC_VERSION_MAJOR < 52
163 context->bits_per_sample = vs->bits_per_sample;
164 #endif
165 context->codec_type = CODEC_TYPE_VIDEO;
166 } else if (stream->GetType () == MediaTypeAudio) {
167 AudioStream *as = (AudioStream*) stream;
168 context->sample_rate = as->GetSampleRate ();
169 context->channels = as->GetChannels ();
170 context->bit_rate = as->GetBitRate ();
171 context->block_align = as->GetBlockAlign ();
172 context->codec_type = CODEC_TYPE_AUDIO;
173 audio_buffer = (guint8*) av_mallocz (AUDIO_BUFFER_SIZE);
174 } else {
175 result = MEDIA_FAIL;
176 Media::Warning (MEDIA_FAIL, "Invalid stream type.");
177 goto failure;
180 ffmpeg_result = avcodec_open (context, codec);
181 if (ffmpeg_result < 0) {
182 result = MEDIA_CODEC_ERROR;
183 Media::Warning (MEDIA_CODEC_ERROR, "Failed to open codec (result: %d = %s).", ffmpeg_result, strerror (AVERROR (ffmpeg_result)));
184 goto failure;
187 SetPixelFormat (FfmpegDecoder::ToMoonPixFmt (context->pix_fmt));
189 //printf ("FfmpegDecoder::Open (): Opened codec successfully.\n");
191 pthread_mutex_unlock (&ffmpeg_mutex);
193 return result;
195 failure:
196 if (context != NULL) {
197 if (context->codec != NULL) {
198 avcodec_close (context);
200 if (context->extradata != NULL) {
201 av_free (context->extradata);
202 context->extradata = NULL;
204 av_free (context);
205 context = NULL;
207 pthread_mutex_unlock (&ffmpeg_mutex);
209 return result;
212 void
213 FfmpegDecoder::Dispose ()
215 pthread_mutex_lock (&ffmpeg_mutex);
217 if (context != NULL) {
218 if (context->codec != NULL) {
219 avcodec_close (context);
221 if (context->extradata != NULL) {
222 av_free (context->extradata);
223 context->extradata = NULL;
225 av_free (context);
226 context = NULL;
229 av_free (audio_buffer);
230 audio_buffer = NULL;
232 if (frame_buffer != NULL) {
233 g_free (frame_buffer);
234 frame_buffer = NULL;
237 pthread_mutex_unlock (&ffmpeg_mutex);
239 IMediaDecoder::Dispose ();
242 void
243 FfmpegDecoder::Cleanup (MediaFrame *frame)
245 AVFrame *av_frame = (AVFrame *) frame->decoder_specific_data;
247 if (av_frame != NULL) {
248 if (av_frame->data[0] != frame->data_stride[0]) {
249 for (int i = 0; i < 4; i++)
250 free (frame->data_stride[i]);
253 frame->decoder_specific_data = NULL;
254 av_free (av_frame);
258 void
259 FfmpegDecoder::CleanState ()
261 int length;
262 AVFrame *frame = NULL;
263 int got_picture = 0;
264 IMediaStream *stream = GetStream ();
266 LOG_FFMPEG ("FfmpegDecoder::CleanState ()\n");
268 has_delayed_frame = false;
269 last_pts = G_MAXUINT64;
271 if (context != NULL) {
272 // This is what ffmpeg says you should do.
273 avcodec_flush_buffers (context);
275 // The above doesn't seem to be implemented for wmv/vc1 codecs though, so do it the hard way.
276 if (stream->GetType () != MediaTypeVideo)
277 return; // This is only an issue for video codecs
279 frame = avcodec_alloc_frame ();
280 length = avcodec_decode_video (context, frame, &got_picture, NULL, 0);
281 av_free (frame);
285 void
286 FfmpegDecoder::DecodeFrameAsyncInternal (MediaFrame *mf)
288 IMediaStream *stream = GetStream ();
289 AVFrame *frame = NULL;
290 guint64 prev_pts;
291 //guint64 input_pts = mf->pts;
292 int got_picture = 0;
293 int length = 0;
295 LOG_FFMPEG ("FfmpegDecoder::DecodeFrame (%p). pts: %" G_GUINT64_FORMAT " ms, context: %p\n", mf, MilliSeconds_FromPts (mf->pts), context);
297 if (context == NULL) {
298 ReportErrorOccurred (MEDIA_FAIL);
299 return;
302 if (stream->GetType () == MediaTypeVideo) {
303 frame = avcodec_alloc_frame ();
304 prev_pts = last_pts;
305 last_pts = mf->pts;
307 length = avcodec_decode_video (context, frame, &got_picture, mf->buffer, mf->buflen);
309 if (length < 0 || !got_picture) {
310 av_free (frame);
311 // This is normally because the codec is a delayed codec,
312 // the first decoding request doesn't give any result,
313 // then every subsequent request returns the previous frame.
314 // TODO: Find a way to get the last frame out of ffmpeg
315 // (requires passing NULL as buffer and 0 as buflen)
316 if (has_delayed_frame) {
317 Media::Warning (MEDIA_CODEC_ERROR, "Error while decoding frame (got length: %d).", length);
318 ReportErrorOccurred (MEDIA_CODEC_ERROR);
319 return;
320 } else {
321 //Media::Warning (MEDIA_CODEC_ERROR, "Error while decoding frame (got length: %d), delaying.", length);
322 has_delayed_frame = true;
323 // return MEDIA_CODEC_DELAYED;
324 return;
328 if (prev_pts != G_MAXUINT64 && has_delayed_frame)
329 mf->pts = prev_pts;
331 LOG_FFMPEG ("FfmpegDecoder::DecodeFrame (%p): got picture, actual pts: %" G_GUINT64_FORMAT ", has delayed frame: %i, prev_pts: %" G_GUINT64_FORMAT " ms\n",
332 mf, MilliSeconds_FromPts (mf->pts), has_delayed_frame, MilliSeconds_FromPts (prev_pts));
334 mf->AddState (MediaFramePlanar);
336 g_free (mf->buffer);
337 mf->buffer = NULL;
338 mf->buflen = 0;
340 mf->srcSlideY = 0;
341 mf->srcSlideH = context->height;
343 int height = context->height;
344 int plane_bytes [4];
346 switch (GetPixelFormat ()) {
347 case MoonPixelFormatYUV420P:
348 plane_bytes [0] = height * frame->linesize [0];
349 plane_bytes [1] = height * frame->linesize [1] / 2;
350 plane_bytes [2] = height * frame->linesize [2] / 2;
351 plane_bytes [3] = 0;
352 break;
353 default:
354 printf ("FfmpegDecoder::DecodeFrame (): Unknown output format, can't calculate byte number.\n");
355 plane_bytes [0] = 0;
356 plane_bytes [1] = 0;
357 plane_bytes [2] = 0;
358 plane_bytes [3] = 0;
359 break;
362 for (int i = 0; i < 4; i++) {
363 if (plane_bytes [i] != 0) {
364 if (posix_memalign ((void **)&mf->data_stride [i], 16, plane_bytes[i] + stream->min_padding)) {
365 g_warning ("Could not allocate memory for data stride");
366 av_free (frame);
367 ReportErrorOccurred (MEDIA_OUT_OF_MEMORY);
368 return;
370 memcpy (mf->data_stride[i], frame->data[i], plane_bytes[i]);
371 } else {
372 mf->data_stride[i] = frame->data[i];
375 mf->srcStride[i] = frame->linesize[i];
378 // We can't free the frame until the data has been used,
379 // so save the frame in decoder_specific_data.
380 // This will cause FfmpegDecoder::Cleanup to be called
381 // when the MediaFrame is deleted.
382 // TODO: check if we can free this now, given that we always copy data out from ffmpeg's buffers
383 mf->decoder_specific_data = frame;
384 } else if (stream->GetType () == MediaTypeAudio) {
385 MpegFrameHeader mpeg;
386 int remain = mf->buflen;
387 int offset = 0;
388 int decoded_size = 0;
389 guint8 *decoded_frames = NULL;
391 LOG_FFMPEG ("FfmpegDecoder::DecodeFrame (), got %i bytes to decode.\n", mf->buflen);
393 if (frame_buffer != NULL) {
394 // copy data previously not decoded in front of this data
395 LOG_FFMPEG ("FfmpegDecoder::DecodeFrame (), adding %i bytes previously not decoded.\n", frame_buffer_length);
396 mf->buffer = (guint8 *) g_realloc (mf->buffer, mf->buflen+frame_buffer_length);
397 memmove (mf->buffer + frame_buffer_length, mf->buffer, mf->buflen);
398 memcpy (mf->buffer, frame_buffer, frame_buffer_length);
399 remain += frame_buffer_length;
401 g_free (frame_buffer);
402 frame_buffer = NULL;
403 mf->buflen += frame_buffer_length;
406 do {
407 int frame_size;
408 int buffer_size = AUDIO_BUFFER_SIZE;
410 if (stream->codec_id == CODEC_MP3 && mpeg_parse_header (&mpeg, mf->buffer+offset)) {
411 frame_size = mpeg_frame_length (&mpeg, false);
413 if (frame_size > remain) {
414 // the remaining data is not a complete mp3 frame
415 // save it and decode it next time we're called.
416 frame_buffer_length = remain;
417 frame_buffer = (guint8 *) g_memdup (mf->buffer + offset, remain);
418 remain = 0;
419 continue;
421 } else {
422 frame_size = mf->buflen - offset;
425 length = avcodec_decode_audio2 (context, (gint16 *) audio_buffer, &buffer_size, mf->buffer+offset, frame_size);
427 if (length <= 0 || buffer_size < frame_size) {
428 //Media::Warning (MEDIA_CODEC_ERROR, "Error while decoding audio frame (length: %d, frame_size. %d, buflen: %u).", length, frame_size, mf->buflen);
429 ReportErrorOccurred (MEDIA_CODEC_ERROR);
430 return;
433 LOG_FFMPEG ("FfmpegDecoder::DecodeFrame (), used %i bytes of %i input bytes to get %i output bytes\n", length, mf->buflen, buffer_size);
435 if (buffer_size > 0) {
436 decoded_frames = (guint8 *) g_realloc (decoded_frames, buffer_size+decoded_size);
437 memcpy (decoded_frames+decoded_size, audio_buffer, buffer_size);
438 offset += length;
439 remain -= length;
440 decoded_size += buffer_size;
441 } else {
442 if (decoded_frames != NULL)
443 g_free (decoded_frames);
444 decoded_frames = NULL;
445 remain = 0;
446 decoded_size = 0;
448 } while (remain > 0);
450 g_free (mf->buffer);
452 mf->buffer = decoded_frames;
453 mf->buflen = decoded_size;;
455 LOG_FFMPEG ("FfmpegDecoder::DecodeFrame (), got a total of %i output bytes.\n", mf->buflen);
456 } else {
457 ReportErrorOccurred ("Invalid media type.");
458 return;
461 mf->AddState (MediaFrameDecoded);
463 ReportDecodeFrameCompleted (mf);
467 * FfmpegDecoderInfo
470 bool
471 FfmpegDecoderInfo::Supports (const char* codec)
473 return avcodec_find_decoder_by_name (codec) != NULL;
476 IMediaDecoder*
477 FfmpegDecoderInfo::Create (Media* media, IMediaStream* stream)
479 return new FfmpegDecoder (media, stream);
483 * FfmpegDemuxer
486 FfmpegDemuxer::FfmpegDemuxer (Media *media, IMediaSource *source)
487 : IMediaDemuxer (Type::FFMPEGDEMUXER, media, source)