Revert "Fix build with latest FFmpeg."
[gnash.git] / libmedia / ffmpeg / MediaParserFfmpeg.cpp
blobd6e6902c0872141bc8b39cfa9f6985ced24454b2
1 // MediaParserFfmpeg.cpp: FFMPEG media parsers, for Gnash
2 //
3 // Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012
4 // Free Software Foundation, Inc.
5 //
6 // This program is free software; you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation; either version 3 of the License, or
9 // (at your option) any later version.
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software
18 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 #include "ffmpegHeaders.h"
22 #include "MediaParserFfmpeg.h"
23 #include "GnashException.h"
24 #include "log.h"
25 #include "IOChannel.h"
27 //#define GNASH_ALLOW_VCODEC_ENV 1
28 // Set this to enable a special GNASH_DEFAULT_VCODEC environment variable, which
29 // is used as a default when the video codec can't be detected. This is a quick
30 // hack to make MJPEG HTTP videos work (which can't be detected as their MIME
31 // type is just "mixed/multipart"). Perhaps the codec will be configurable via
32 // ActionScript sometime. - Udo
34 namespace gnash {
35 namespace media {
36 namespace ffmpeg {
38 namespace {
40 // Used to calculate a decimal value from a ffmpeg fraction
41 inline double as_double(AVRational time) {
42 return time.num / static_cast<double>(time.den);
45 } // anonymous namespace
48 int
49 MediaParserFfmpeg::readPacketWrapper(void* opaque, boost::uint8_t* buf,
50 int buf_size)
52 MediaParserFfmpeg* p = static_cast<MediaParserFfmpeg*>(opaque);
53 return p->readPacket(buf, buf_size);
56 boost::int64_t
57 MediaParserFfmpeg::seekMediaWrapper(void *opaque, boost::int64_t offset, int whence)
59 MediaParserFfmpeg* p = static_cast<MediaParserFfmpeg*>(opaque);
60 return p->seekMedia(offset, whence);
63 AVInputFormat*
64 MediaParserFfmpeg::probeStream()
66 const size_t probeSize = 4096;
67 const size_t bufSize = probeSize + FF_INPUT_BUFFER_PADDING_SIZE;
69 boost::scoped_array<boost::uint8_t> buffer(new boost::uint8_t[bufSize]);
71 assert(_stream->tell() == static_cast<std::streampos>(0));
72 size_t actuallyRead = _stream->read(buffer.get(), probeSize);
74 // Fill any padding with 0s.
75 std::fill(buffer.get() + actuallyRead, buffer.get() + bufSize, 0);
77 _stream->seek(0);
79 if (actuallyRead < 1) {
80 throw IOException(_("MediaParserFfmpeg could not read probe data "
81 "from input"));
84 // Probe the file to detect the format
85 AVProbeData probe_data;
86 probe_data.filename = "";
87 probe_data.buf = buffer.get();
88 probe_data.buf_size = actuallyRead;
90 AVInputFormat* ret = av_probe_input_format(&probe_data, 1);
91 return ret;
94 bool
95 MediaParserFfmpeg::seek(boost::uint32_t& pos)
97 // lock the stream while reading from it, so actionscript
98 // won't mess with the parser on seek or on getBytesLoaded
99 boost::mutex::scoped_lock streamLock(_streamMutex);
101 // NOTE: seeking when timestamps are unknown is a pain
102 // See https://savannah.gnu.org/bugs/index.php?33085
103 // TODO: newer ffmpeg versions seem to have an
104 // av_seek_frame_generic() function
105 // which may help us. May be worth taking a look
107 if ( pos == 0 ) {
108 // Handle 0 by seeking to byte 0
109 // Doing this saves lots of headakes in absence
110 // of correct timestamps (which is the case for mp3)
111 log_debug("Seeking MediaParserFfmpeg input to byte offset zero");
112 if (av_seek_frame(_formatCtx, -1, pos, AVSEEK_FLAG_BYTE) < 0) {
113 log_error(_("%s: seeking failed"), __FUNCTION__);
114 return 0;
117 else {
118 // This is most likely wrong
119 log_debug("MediaParserFfmpeg::seek(%d) TESTING", pos);
120 long newpos = static_cast<long>(pos / AV_TIME_BASE);
121 if (av_seek_frame(_formatCtx, -1, newpos, 0) < 0) {
122 log_error(_("%s: seeking failed"), __FUNCTION__);
123 return 0;
127 // We'll restart parsing
128 _parsingComplete = false;
130 // Finally, clear the buffers.
131 // The call will also wake the parse up if it was sleeping.
132 // WARNING: a race condition might be pending here:
133 // If we handled to do all the seek work in the *small*
134 // time that the parser runs w/out mutex locked (ie:
135 // after it unlocked the stream mutex and before it locked
136 // the queue mutex), it will still push an old encoded frame
137 // to the queue; if the pushed frame alone makes it block
138 // again (bufferFull) we'll have a problem.
139 // Note though, that a single frame can't reach a bufferFull
140 // condition, as it takes at least two for anything != 0.
142 clearBuffers();
144 return true;
147 bool
148 MediaParserFfmpeg::parseVideoFrame(AVPacket& packet)
150 assert(packet.stream_index == _videoStreamIndex);
151 assert(_videoStream);
153 // packet.dts is "decompression" timestamp
154 // packet.pts is "presentation" timestamp
155 // Dunno why we use dts, and don't understand the magic formula either...
157 // From ffmpeg dox:
158 // pkt->pts can be AV_NOPTS_VALUE if the video format has B frames,
159 // so it is better to rely on pkt->dts if you do not decompress the payload.
161 boost::uint64_t timestamp = static_cast<boost::uint64_t>(packet.dts * as_double(_videoStream->time_base) * 1000.0);
163 #if 0
164 LOG_ONCE( log_unimpl("%s", __PRETTY_FUNCTION__) );
165 return false;
166 #else
168 // flags, for keyframe
169 //bool isKeyFrame = packet.flags&PKT_FLAG_KEY;
171 // TODO: FIXME: *2 is an hack to avoid libavcodec reading past end of allocated space
172 // we might do proper padding or (better) avoid the copy as a whole by making
173 // EncodedVideoFrame virtual.
174 size_t allocSize = packet.size*2;
175 boost::uint8_t* data = new boost::uint8_t[allocSize];
176 std::copy(packet.data, packet.data+packet.size, data);
177 std::auto_ptr<EncodedVideoFrame> frame(new EncodedVideoFrame(data, packet.size, 0, timestamp));
179 pushEncodedVideoFrame(frame);
181 return true;
182 #endif
185 bool
186 MediaParserFfmpeg::parseAudioFrame(AVPacket& packet)
188 assert(packet.stream_index == _audioStreamIndex);
189 assert(_audioStream);
191 // packet.dts is "decompression" timestamp
192 // packet.pts is "presentation" timestamp
193 // Dunno why we use dts, and don't understand the magic formula either...
195 // From ffmpeg dox:
196 // pkt->pts can be AV_NOPTS_VALUE if the video format has B frames,
197 // so it is better to rely on pkt->dts if you do not decompress the payload.
200 boost::uint64_t dts = packet.dts;
201 if ( dts == static_cast<boost::uint64_t>(AV_NOPTS_VALUE) ) {
202 // We'll take 'nopts' value as zero.
203 // Would likely be better to make it use timestamp
204 // of previous frame, if any.
206 // For now, this handling fixes warnings like:
207 // mdb:93, lastbuf:0 skiping granule 0
208 // mdb:93, lastbuf:0 skiping granule 0
209 // When playing: http://downloads.bbc.co.uk/news/nol/shared/spl/hi/audio_slideshow/kenadamptw/slideshow_629.swf
211 LOG_ONCE(log_error(_("FIXME: FFmpeg packet decompression "
212 "timestamp has no value, taking as zero")));
213 dts = 0;
215 boost::uint64_t timestamp = static_cast<boost::uint64_t>(dts * as_double(_audioStream->time_base) * 1000.0);
216 //log_debug("On getting audio frame with timestamp %d, duration is %d", timestamp, _audioStream->duration);
218 std::auto_ptr<EncodedAudioFrame> frame ( new EncodedAudioFrame );
220 // TODO: FIXME: *2 is an hack to avoid libavcodec reading past end of allocated space
221 // we might do proper padding or (better) avoid the copy as a whole by making
222 // EncodedVideoFrame virtual.
223 size_t allocSize = packet.size*2;
224 boost::uint8_t* data = new boost::uint8_t[allocSize];
225 std::copy(packet.data, packet.data+packet.size, data);
227 frame->data.reset(data);
228 frame->dataSize = packet.size;
229 frame->timestamp = timestamp;
231 pushEncodedAudioFrame(frame);
233 return true;
236 bool
237 MediaParserFfmpeg::parseNextFrame()
239 // lock the stream while reading from it, so actionscript
240 // won't mess with the parser on seek or on getBytesLoaded
241 boost::mutex::scoped_lock streamLock(_streamMutex);
243 if ( _parsingComplete )
245 //log_debug("MediaParserFfmpeg::parseNextFrame: parsing "
246 //"complete, nothing to do");
247 return false;
250 // position the stream where we left parsing as
251 // it could be somewhere else for reading a specific
252 // or seeking.
253 //_stream->seek(_lastParsedPosition);
255 assert(_formatCtx);
257 AVPacket packet;
259 //log_debug("av_read_frame call");
260 int rc = av_read_frame(_formatCtx, &packet);
262 // Update _lastParsedPosition, even in case of error..
263 boost::uint64_t curPos = _stream->tell();
264 if ( curPos > _lastParsedPosition )
266 _lastParsedPosition = curPos;
269 //log_debug("av_read_frame returned %d", rc);
270 if ( rc < 0 )
272 log_error(_("MediaParserFfmpeg::parseNextFrame: "
273 "Problems parsing next frame "
274 "(av_read_frame returned %d)."
275 " We'll consider the stream fully parsed."), rc);
276 _parsingComplete=true; // No point in parsing over
277 return false;
280 bool ret = false;
282 if ( packet.stream_index == _videoStreamIndex )
284 ret = parseVideoFrame(packet);
286 else if ( packet.stream_index == _audioStreamIndex )
288 ret = parseAudioFrame(packet);
290 else
292 ret = false; // redundant..
293 log_debug("MediaParserFfmpeg::parseNextFrame: unknown stream index %d",
294 packet.stream_index);
297 av_free_packet(&packet);
299 // Check if EOF was reached
300 if ( _stream->eof() )
302 log_debug("MediaParserFfmpeg::parseNextFrame: at eof after "
303 "av_read_frame");
304 _parsingComplete=true;
307 return ret;
310 bool
311 MediaParserFfmpeg::parseNextChunk()
313 if (!parseNextFrame()) return false;
314 return true;
317 boost::uint64_t
318 MediaParserFfmpeg::getBytesLoaded() const
320 return _lastParsedPosition;
323 MediaParserFfmpeg::MediaParserFfmpeg(std::auto_ptr<IOChannel> stream)
325 MediaParser(stream),
326 _nextVideoFrame(0),
327 _nextAudioFrame(0),
328 _inputFmt(0),
329 _formatCtx(0),
330 _videoStreamIndex(-1),
331 _videoStream(0),
332 _audioStreamIndex(-1),
333 _audioStream(0),
334 _lastParsedPosition(0)
336 initializeParser();
338 startParserThread();
341 /*private*/
342 void
343 MediaParserFfmpeg::initializeParser()
345 av_register_all(); // TODO: needs to be invoked only once ?
347 _byteIOCxt.buffer = NULL;
349 _inputFmt = probeStream();
351 #ifdef GNASH_ALLOW_VCODEC_ENV
352 if (!_inputFmt) {
353 char* defcodec = getenv("GNASH_DEFAULT_VCODEC");
354 if (defcodec && strlen(defcodec)) {
355 _inputFmt = av_find_input_format(defcodec);
358 #endif
359 if (! _inputFmt) {
360 throw MediaException("MediaParserFfmpeg couldn't figure out input "
361 "format");
364 // Setup the filereader/seeker mechanism.
365 // 7th argument (NULL) is the writer function,
366 // which isn't needed.
367 _byteIOBuffer.reset(new unsigned char[byteIOBufferSize]);
369 init_put_byte(&_byteIOCxt,
370 _byteIOBuffer.get(), // buffer
371 byteIOBufferSize, // buffer size
372 0, // write flags
373 this, // opaque pointer to pass to the callbacks
374 MediaParserFfmpeg::readPacketWrapper, // packet reader callback
375 NULL, // packet writer callback
376 MediaParserFfmpeg::seekMediaWrapper // seeker callback
379 _byteIOCxt.is_streamed = 1;
381 #if !defined(LIBAVCODEC_VERSION_MAJOR) || LIBAVCODEC_VERSION_MAJOR < 52
382 // Needed for Lenny.
383 _formatCtx = av_alloc_format_context();
384 #else
385 _formatCtx = avformat_alloc_context();
386 #endif
388 assert(_formatCtx);
390 // Otherwise av_open_input_stream will reallocate the context.
391 AVFormatParameters ap;
392 std::memset(&ap, 0, sizeof ap);
393 ap.prealloced_context = 1;
395 if (av_open_input_stream(&_formatCtx, &_byteIOCxt, "", _inputFmt, &ap) < 0)
397 throw IOException("MediaParserFfmpeg couldn't open input stream");
400 #if defined(LIBAVCODEC_VERSION_MAJOR) && LIBAVCODEC_VERSION_MAJOR >= 52
401 // Note: in at least some versions of ffmpeg, av_open_input_stream does
402 // not parse metadata; not sure why.
403 AVMetadata* md = _formatCtx->metadata;
404 if (md) {
405 AVMetadataTag* tag = av_metadata_get(md, "album", 0,
406 AV_METADATA_MATCH_CASE);
407 if (tag && tag->value) {
408 setId3Info(&Id3Info::album, std::string(tag->value),
409 _id3Object);
412 #endif
414 log_debug("Parsing FFMPEG media file: format:%s; nstreams:%d",
415 _inputFmt->name, _formatCtx->nb_streams);
417 // Find first audio and video stream
418 for (size_t i = 0; i < static_cast<size_t>(_formatCtx->nb_streams); ++i) {
420 AVStream* stream = _formatCtx->streams[i];
421 if (! stream) {
422 log_debug("Stream %d of FFMPEG media file is null ?", i);
423 continue;
426 AVCodecContext* enc = stream->codec;
427 if (!enc) {
428 log_debug("Stream %d of FFMPEG media file has no codec info", i);
429 continue;
432 switch (enc->codec_type) {
433 #if LIBAVCODEC_VERSION_MAJOR >= 53
434 case AVMEDIA_TYPE_AUDIO:
435 #else
436 case CODEC_TYPE_AUDIO:
437 #endif
438 if (_audioStreamIndex < 0) {
439 _audioStreamIndex = i;
440 _audioStream = _formatCtx->streams[i];
441 // codec_name will only be filled by avcodec_find_decoder
442 // (later);
443 log_debug(_(" Using stream %d for audio: codec id %d"),
444 i, _audioStream->codec->codec_id);
446 break;
448 #if LIBAVCODEC_VERSION_MAJOR >= 53
449 case AVMEDIA_TYPE_VIDEO:
450 #else
451 case CODEC_TYPE_VIDEO:
452 #endif
453 if (_videoStreamIndex < 0) {
454 _videoStreamIndex = i;
455 _videoStream = _formatCtx->streams[i];
456 log_debug(_(" Using stream %d for video: codec id %d"),
457 i, _videoStream->codec->codec_id);
459 break;
460 default:
461 break;
465 // Create VideoInfo
466 if ( _videoStream) {
467 const int codec = static_cast<int>(_videoStream->codec->codec_id);
468 boost::uint16_t width = _videoStream->codec->width;
469 boost::uint16_t height = _videoStream->codec->height;
470 boost::uint16_t frameRate = static_cast<boost::uint16_t>(
471 as_double(_videoStream->r_frame_rate));
472 #if !defined(HAVE_LIBAVFORMAT_AVFORMAT_H) && !defined(HAVE_FFMPEG_AVCODEC_H)
473 boost::uint64_t duration = _videoStream->codec_info_duration;
474 #else
475 boost::uint64_t duration = _videoStream->duration;
476 #endif
477 if (duration == AV_NOPTS_VALUE) {
478 log_error(_("Duration of video stream unknown"));
479 duration=0; // TODO: guess!
480 } else {
481 duration = duration / as_double(_videoStream->time_base); // TODO: check this
484 _videoInfo.reset(new VideoInfo(codec, width, height, frameRate,
485 duration, CODEC_TYPE_CUSTOM /*codec type*/));
487 // NOTE: AVCodecContext.extradata : void* for 51.11.0, uint8_t* for 51.38.0
488 _videoInfo->extra.reset(new ExtraVideoInfoFfmpeg(
489 (uint8_t*)_videoStream->codec->extradata,
490 _videoStream->codec->extradata_size));
494 // Create AudioInfo
495 if (_audioStream) {
497 const int codec = static_cast<int>(_audioStream->codec->codec_id);
498 boost::uint16_t sampleRate = _audioStream->codec->sample_rate;
499 boost::uint16_t sampleSize = SampleFormatToSampleSize(_audioStream->codec->sample_fmt);
500 bool stereo = (_audioStream->codec->channels == 2);
501 #if !defined(HAVE_LIBAVFORMAT_AVFORMAT_H) && !defined(HAVE_FFMPEG_AVCODEC_H)
502 boost::uint64_t duration = _audioStream->codec_info_duration;
503 #else
504 boost::uint64_t duration = _audioStream->duration;
505 #endif
506 if (duration == AV_NOPTS_VALUE) {
507 log_error(_("Duration of audio stream unknown to ffmpeg"));
508 duration=0; // TODO: guess!
510 else {
511 duration = duration / as_double(_audioStream->time_base); // TODO: check this
514 _audioInfo.reset(new AudioInfo(codec, sampleRate, sampleSize, stereo,
515 duration, CODEC_TYPE_CUSTOM /*codec type*/));
517 // NOTE: AVCodecContext.extradata : void* for 51.11.0, uint8_t* for 51.38.0
518 _audioInfo->extra.reset(new ExtraAudioInfoFfmpeg(
519 (uint8_t*)_audioStream->codec->extradata,
520 _audioStream->codec->extradata_size));
527 MediaParserFfmpeg::~MediaParserFfmpeg()
529 stopParserThread();
531 if ( _formatCtx )
533 // TODO: check if this is correct (should we create RIIA classes for ffmpeg stuff?)
534 //av_close_input_file(_formatCtx); // NOTE: this one triggers a mismatched free/delete on _byteIOBuffer with libavformat.so.52 !
535 av_free(_formatCtx);
538 if ( _inputFmt )
540 // TODO: check if this is correct (should we create RIIA classes for ffmpeg stuff?)
541 //av_free(_inputFmt); // it seems this one blows up, could be due to av_free(_formatCtx) above
546 // NOTE: as this function is used as a callback from FFMPEG, it should not
547 // throw any exceptions, because:
548 // a) The behaviour of C++ exceptions passed into C code is undefined.
549 // b) Even if we don't crash and burn, the FFMPEG parser is left in an
550 // undefined state.
551 int
552 MediaParserFfmpeg::readPacket(boost::uint8_t* buf, int buf_size)
554 //GNASH_REPORT_FUNCTION;
555 //log_debug("readPacket(%d)", buf_size);
557 size_t ret = _stream->read(static_cast<void*>(buf), buf_size);
559 return ret;
563 boost::optional<Id3Info>
564 MediaParserFfmpeg::getId3Info() const
566 return _id3Object;
569 // NOTE: as this function is used as a callback from FFMPEG, it should not
570 // throw any exceptions, because:
571 // a) The behaviour of C++ exceptions passed into C code is undefined.
572 // b) Even if we don't crash and burn, the FFMPEG parser is left in an
573 // undefined state.
574 boost::int64_t
575 MediaParserFfmpeg::seekMedia(boost::int64_t offset, int whence)
577 //GNASH_REPORT_FUNCTION;
578 //log_debug("::seekMedia(%1%, %2%)", offset, whence);
580 assert(_stream.get());
582 if (whence == SEEK_SET)
584 // Offset is absolute new position in the file
585 if ( offset < 0 ) {
586 boost::format fmt = boost::format(
587 _("MediaParserFfmpeg couldn't parse input format: "
588 "tried to seek at negative offset %1%."))
589 % offset;
590 log_error(fmt);
591 return -1;
592 } else {
593 _stream->seek(offset);
596 else if (whence == SEEK_CUR)
598 // New position is offset + old position
599 _stream->seek(_stream->tell() + static_cast<std::streamoff>(offset));
601 else if (whence == SEEK_END)
603 // New position is offset + end of file
604 log_unimpl("MediaParserFfmpeg seek from end of file");
605 // This is (most likely) a streamed file, so we can't seek to the end!
606 // Instead we seek to byteIOBufferSize bytes... seems to work fine...
607 _stream->seek(byteIOBufferSize);
610 else
612 // ffmpeg uses whence=AVSEEK_SIZE and offset=0 to request
613 // stream size !
614 log_unimpl("MediaParserFfmpeg: unsupported whence value %d", whence);
615 return -1;
619 return _stream->tell();
622 boost::uint16_t
623 MediaParserFfmpeg::SampleFormatToSampleSize(SampleFormat fmt)
625 switch (fmt)
627 case SAMPLE_FMT_U8: // unsigned 8 bits
628 return 1;
630 case SAMPLE_FMT_S16: // signed 16 bits
631 case SAMPLE_FMT_FLT: // float
632 return 2;
634 #if !defined (LIBAVCODEC_VERSION_MAJOR) || LIBAVCODEC_VERSION_MAJOR < 52
635 // Was dropped for version 52.0.0
636 case SAMPLE_FMT_S24: // signed 24 bits
637 return 3;
638 #endif
640 case SAMPLE_FMT_S32: // signed 32 bits
641 return 4;
643 case SAMPLE_FMT_NONE:
644 default:
645 return 8; // arbitrary value
650 } // gnash.media.ffmpeg namespace
651 } // end of gnash::media namespace
652 } // end of gnash namespace
654 #undef PADDING_BYTES
655 #undef READ_CHUNKS