2 * pipeline-ffmpeg.cpp: Ffmpeg related parts of the pipeline for the media
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.
25 #include "pipeline-ffmpeg.h"
32 bool ffmpeg_initialized
= false;
33 bool ffmpeg_registered
= false;
35 pthread_mutex_t ffmpeg_mutex
= PTHREAD_MUTEX_INITIALIZER
;
40 if (ffmpeg_initialized
)
44 avcodec_register_all ();
46 ffmpeg_initialized
= true;
54 Media::RegisterDecoder (new FfmpegDecoderInfo ());
55 //Media::RegisterDemuxer (new FfmpegDemuxerInfo ());
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
;
74 frame_buffer_length
= 0;
75 last_pts
= G_MAXUINT64
;
79 FfmpegDecoder::ToFfmpegPixFmt (MoonPixelFormat format
)
82 case MoonPixelFormatYUV420P
: return PIX_FMT_YUV420P
;
83 case MoonPixelFormatRGB32
: return PIX_FMT_RGB32
;
85 //printf ("FfmpegDecoder::ToFfmpegPixFmt (%i): Unknown pixel format.\n", format);
91 FfmpegDecoder::ToMoonPixFmt (PixelFormat format
)
94 case PIX_FMT_YUV420P
: return MoonPixelFormatYUV420P
;
95 case PIX_FMT_RGB32
: return MoonPixelFormatRGB32
;
97 //printf ("FfmpegDecoder::ToMoonPixFmt (%i): Unknown pixel format.\n", format);
98 return MoonPixelFormatNone
;
103 FfmpegDecoder::OpenDecoderAsyncInternal ()
109 if (MEDIA_SUCCEEDED (result
)) {
110 ReportOpenDecoderCompleted ();
112 ReportErrorOccurred (result
);
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);
133 result
= MEDIA_UNKNOWN_CODEC
;
134 Media::Warning (MEDIA_UNKNOWN_CODEC
, "Unknown codec: %s", stream
->codec
);
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.");
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.");
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
;
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
);
176 Media::Warning (MEDIA_FAIL
, "Invalid stream type.");
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
)));
187 SetPixelFormat (FfmpegDecoder::ToMoonPixFmt (context
->pix_fmt
));
189 //printf ("FfmpegDecoder::Open (): Opened codec successfully.\n");
191 pthread_mutex_unlock (&ffmpeg_mutex
);
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
;
207 pthread_mutex_unlock (&ffmpeg_mutex
);
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
;
229 av_free (audio_buffer
);
232 if (frame_buffer
!= NULL
) {
233 g_free (frame_buffer
);
237 pthread_mutex_unlock (&ffmpeg_mutex
);
239 IMediaDecoder::Dispose ();
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
;
259 FfmpegDecoder::CleanState ()
262 AVFrame
*frame
= NULL
;
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);
286 FfmpegDecoder::DecodeFrameAsyncInternal (MediaFrame
*mf
)
288 IMediaStream
*stream
= GetStream ();
289 AVFrame
*frame
= NULL
;
291 //guint64 input_pts = mf->pts;
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
);
302 if (stream
->GetType () == MediaTypeVideo
) {
303 frame
= avcodec_alloc_frame ();
307 length
= avcodec_decode_video (context
, frame
, &got_picture
, mf
->buffer
, mf
->buflen
);
309 if (length
< 0 || !got_picture
) {
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
);
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;
328 if (prev_pts
!= G_MAXUINT64
&& has_delayed_frame
)
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
);
341 mf
->srcSlideH
= context
->height
;
343 int height
= context
->height
;
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;
354 printf ("FfmpegDecoder::DecodeFrame (): Unknown output format, can't calculate byte number.\n");
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");
367 ReportErrorOccurred (MEDIA_OUT_OF_MEMORY
);
370 memcpy (mf
->data_stride
[i
], frame
->data
[i
], plane_bytes
[i
]);
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
;
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
);
403 mf
->buflen
+= frame_buffer_length
;
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
);
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
);
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
);
440 decoded_size
+= buffer_size
;
442 if (decoded_frames
!= NULL
)
443 g_free (decoded_frames
);
444 decoded_frames
= NULL
;
448 } while (remain
> 0);
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
);
457 ReportErrorOccurred ("Invalid media type.");
461 mf
->AddState (MediaFrameDecoded
);
463 ReportDecodeFrameCompleted (mf
);
471 FfmpegDecoderInfo::Supports (const char* codec
)
473 return avcodec_find_decoder_by_name (codec
) != NULL
;
477 FfmpegDecoderInfo::Create (Media
* media
, IMediaStream
* stream
)
479 return new FfmpegDecoder (media
, stream
);
486 FfmpegDemuxer::FfmpegDemuxer (Media
*media
, IMediaSource
*source
)
487 : IMediaDemuxer (Type::FFMPEGDEMUXER
, media
, source
)