[haiku-commits] r38401 - haiku/trunk/src/add-ons/media/plugins/ffmpeg

  • From: superstippi@xxxxxx
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Fri, 27 Aug 2010 15:29:52 +0200 (CEST)

Author: stippi
Date: 2010-08-27 15:29:52 +0200 (Fri, 27 Aug 2010)
New Revision: 38401
Changeset: http://dev.haiku-os.org/changeset/38401

Modified:
   haiku/trunk/src/add-ons/media/plugins/ffmpeg/AVFormatReader.cpp
Log:
 * Optionally separate tracing output for FindKeyFrame().
 * Output more information in AVFormatReader::StreamCookie::Open(),
   AVInputFormat flags for example.
 * Added CODEC_ID_AAC handling when codecTag is 0. Adds support
   for AAC in Matroska containers when the ffmpeg plugin is enabled
   to handle those.
 * Added some rounding to frame<->time conversions.
 * AVFormatReader::StreamCookie::Seek() forgot to pass the seek
   flags to av_seek_frame().
 * The most important fix is this, though: There are formats which
   build the keyframe index on the fly, while parsing the stream!!
   These means we can only seek to real keyframes for parts of the
   stream that has already been decoded. Handle this situation by
   assuming we can seek to the requested frame/time. This change
   fixes the use of the AVFormatReader as MP3 reader.
 * Anothe important fix is to ignore the nb_frames member of the
   stream for the total frame count. This makes MP4 movies
   also work perfectly now when the AVFormatReader is used for them.


Modified: haiku/trunk/src/add-ons/media/plugins/ffmpeg/AVFormatReader.cpp
===================================================================
--- haiku/trunk/src/add-ons/media/plugins/ffmpeg/AVFormatReader.cpp     
2010-08-27 13:21:03 UTC (rev 38400)
+++ haiku/trunk/src/add-ons/media/plugins/ffmpeg/AVFormatReader.cpp     
2010-08-27 13:29:52 UTC (rev 38401)
@@ -32,11 +32,13 @@
 #      define TRACE printf
 #      define TRACE_IO(a...)
 #      define TRACE_SEEK(a...)
+#      define TRACE_FIND(a...)
 #      define TRACE_PACKET(a...)
 #else
 #      define TRACE(a...)
 #      define TRACE_IO(a...)
 #      define TRACE_SEEK(a...)
+#      define TRACE_FIND(a...)
 #      define TRACE_PACKET(a...)
 #endif
 
@@ -160,6 +162,8 @@
                        bool                            fReusePacket;
 
                        media_format            fFormat;
+
+                       bool                            
fStreamBuildsIndexWhileReading;
 };
 
 
@@ -175,7 +179,9 @@
        fStream(NULL),
        fVirtualIndex(-1),
 
-       fReusePacket(false)
+       fReusePacket(false),
+
+       fStreamBuildsIndexWhileReading(false)
 {
        memset(&fIOBuffer, 0, sizeof(fIOBuffer));
        memset(&fFormat, 0, sizeof(media_format));
@@ -222,7 +228,17 @@
 
        TRACE("AVFormatReader::StreamCookie::Open() - "
                "av_probe_input_format(): %s\n", inputFormat->name);
+       TRACE("  flags:%s%s%s%s%s\n",
+               (inputFormat->flags & AVFMT_GLOBALHEADER) ? " 
AVFMT_GLOBALHEADER" : "",
+               (inputFormat->flags & AVFMT_NOTIMESTAMPS) ? " 
AVFMT_NOTIMESTAMPS" : "",
+               (inputFormat->flags & AVFMT_GENERIC_INDEX) ? " 
AVFMT_GENERIC_INDEX" : "",
+               (inputFormat->flags & AVFMT_TS_DISCONT) ? " AVFMT_TS_DISCONT" : 
"",
+               (inputFormat->flags & AVFMT_VARIABLE_FPS) ? " 
AVFMT_VARIABLE_FPS" : ""
+       );
 
+       fStreamBuildsIndexWhileReading
+               = (inputFormat->flags & AVFMT_GENERIC_INDEX) != 0;
+
        const DemuxerFormat* demuxerFormat = demuxer_format_for(inputFormat);
        if (demuxerFormat == NULL) {
                // We could support this format, but we don't want to. Bail out.
@@ -257,7 +273,8 @@
        }
 
        TRACE("AVFormatReader::StreamCookie::Open() - "
-               "av_find_stream_info() success!\n");
+               "av_find_stream_info() success! Seek should be by bytes: %d\n",
+               (inputFormat->flags & AVFMT_TS_DISCONT) != 0);
 
        return B_OK;
 }
@@ -426,6 +443,10 @@
                                        description.family = 
B_QUICKTIME_FORMAT_FAMILY;
                                        codecTag = 
B_BENDIAN_TO_HOST_INT32('.mp3');
                                        break;
+                               case CODEC_ID_AAC:
+                                       description.family = 
B_MISC_FORMAT_FAMILY;
+                                       codecTag = 'mp4a';
+                                       break;
                                default:
                                        fprintf(stderr, "ffmpeg codecTag is 
null, codec_id "
                                                "unknown 0x%x\n", 
codecContext->codec_id);
@@ -460,7 +481,7 @@
                                else if (codecContext->codec_id == CODEC_ID_MP2)
                                        description.u.mpeg.id = 
B_MPEG_2_AUDIO_LAYER_2;
                                else if (codecContext->codec_id == CODEC_ID_MP3)
-                                       description.u.mpeg.id = 
B_MPEG_1_AUDIO_LAYER_3;
+                                       description.u.mpeg.id = 
B_MPEG_2_AUDIO_LAYER_3;
                                // TODO: Add some more...
                                else
                                        description.u.mpeg.id = B_MPEG_ANY;
@@ -717,6 +738,13 @@
        double frameRate = FrameRate();
        TRACE("  frameRate: %.4f\n", frameRate);
 
+       if (fStream->start_time != kNoPTSValue) {
+               bigtime_t startTime = 
_ConvertFromStreamTimeBase(fStream->start_time);
+               TRACE("  start_time: %lld or %.5fs\n", startTime,
+                       startTime / 1000000.0);
+               // TODO: Handle start time in FindKeyFrame()?!
+       }
+
        // TODO: This is obviously not working correctly for all stream types...
        // It seems that the calculations here are correct, because they work
        // for a couple of streams and are in line with the documentation, but
@@ -736,15 +764,43 @@
                TRACE("  stream duration: N/A\n");
        }
 
-       TRACE("  duration: %lld or %.2fs\n", *duration, *duration / 1000000.0);
+       TRACE("  duration: %lld or %.5fs\n", *duration, *duration / 1000000.0);
 
+       #if 0
+       if (fStream->nb_index_entries > 0) {
+               TRACE("  dump of index entries:\n");
+               int count = 5;
+               int firstEntriesCount = min_c(fStream->nb_index_entries, count);
+               int i = 0;
+               for (; i < firstEntriesCount; i++) {
+                       AVIndexEntry& entry = fStream->index_entries[i];
+                       bigtime_t timeGlobal = entry.timestamp;
+                       bigtime_t timeNative = 
_ConvertFromStreamTimeBase(timeGlobal);
+                       TRACE("    [%d] native: %.5fs global: %.5fs\n", i,
+                               timeNative / 1000000.0f, timeGlobal / 
1000000.0f);
+               }
+               if (fStream->nb_index_entries - count > i) {
+                       i = fStream->nb_index_entries - count;
+                       TRACE("    ...\n");
+                       for (; i < fStream->nb_index_entries; i++) {
+                               AVIndexEntry& entry = fStream->index_entries[i];
+                               bigtime_t timeGlobal = entry.timestamp;
+                               bigtime_t timeNative = 
_ConvertFromStreamTimeBase(timeGlobal);
+                               TRACE("    [%d] native: %.5fs global: %.5fs\n", 
i,
+                                       timeNative / 1000000.0f, timeGlobal / 
1000000.0f);
+                       }
+               }
+       }
+       #endif
+
        *frameCount = fStream->nb_frames;
-       if (*frameCount == 0) {
+//     if (*frameCount == 0) {
                // Calculate from duration and frame rate
                *frameCount = (int64)(*duration * frameRate / 1000000LL);
-               TRACE("  frameCount (calculated): %lld\n", *frameCount);
-       } else
-               TRACE("  frameCount: %lld\n", *frameCount);
+               TRACE("  frameCount calculated: %lld, from context: %lld\n",
+                       *frameCount, fStream->nb_frames);
+//     } else
+//             TRACE("  frameCount: %lld\n", *frameCount);
 
        *format = fFormat;
 
@@ -762,18 +818,18 @@
        if (fContext == NULL || fStream == NULL)
                return B_NO_INIT;
 
-       TRACE_SEEK("AVFormatReader::StreamCookie::Seek(%ld, %s %s %s %s, %lld, "
+       TRACE_SEEK("AVFormatReader::StreamCookie::Seek(%ld,%s%s%s%s, %lld, "
                "%lld)\n", VirtualIndex(),
-               (flags & B_MEDIA_SEEK_TO_FRAME) ? "B_MEDIA_SEEK_TO_FRAME" : "",
-               (flags & B_MEDIA_SEEK_TO_TIME) ? "B_MEDIA_SEEK_TO_TIME" : "",
-               (flags & B_MEDIA_SEEK_CLOSEST_BACKWARD) ? 
"B_MEDIA_SEEK_CLOSEST_BACKWARD" : "",
-               (flags & B_MEDIA_SEEK_CLOSEST_FORWARD) ? 
"B_MEDIA_SEEK_CLOSEST_FORWARD" : "",
+               (flags & B_MEDIA_SEEK_TO_FRAME) ? " B_MEDIA_SEEK_TO_FRAME" : "",
+               (flags & B_MEDIA_SEEK_TO_TIME) ? " B_MEDIA_SEEK_TO_TIME" : "",
+               (flags & B_MEDIA_SEEK_CLOSEST_BACKWARD) ? " 
B_MEDIA_SEEK_CLOSEST_BACKWARD" : "",
+               (flags & B_MEDIA_SEEK_CLOSEST_FORWARD) ? " 
B_MEDIA_SEEK_CLOSEST_FORWARD" : "",
                *frame, *time);
 
        // Seeking is always based on time, initialize it when client seeks
        // based on frame.
        if ((flags & B_MEDIA_SEEK_TO_FRAME) != 0)
-               *time = (bigtime_t)(*frame * 1000000LL / FrameRate());
+               *time = (bigtime_t)(*frame * 1000000LL / FrameRate() + 0.5);
 
 #if 0
        // This happens in ffplay.c:
@@ -799,10 +855,25 @@
                *time / 1000000.0, timeStamp, fStream->cur_dts, 
fStream->time_base.num,
                fStream->time_base.den);
 
-       if (av_seek_frame(fContext, Index(), timeStamp, 0) < 0) {
+       int searchFlags = AVSEEK_FLAG_BACKWARD;
+       if ((flags & B_MEDIA_SEEK_CLOSEST_FORWARD) != 0)
+               searchFlags = 0;
+
+#if 0
+       bigtime_t oneSecond = 1000000;
+       int64_t minTimeStamp = timeStamp - _ConvertToStreamTimeBase(oneSecond);
+       int64_t maxTimeStamp = timeStamp + _ConvertToStreamTimeBase(oneSecond);
+       if (avformat_seek_file(fContext, Index(), minTimeStamp, timeStamp,
+               maxTimeStamp, searchFlags) < 0) {
+               TRACE_SEEK("  avformat_seek_file() failed.\n");
+               return B_ERROR;
+       }
+#else
+       if (av_seek_frame(fContext, Index(), timeStamp, searchFlags) < 0) {
                TRACE_SEEK("  av_seek_frame() failed.\n");
                return B_ERROR;
        }
+#endif
 
        // Our last packet is toast in any case.
        av_free_packet(&fPacket);
@@ -819,21 +890,21 @@
        if (fContext == NULL || fStream == NULL)
                return B_NO_INIT;
 
-       TRACE_SEEK("AVFormatReader::StreamCookie::FindKeyFrame(%ld, %s %s %s 
%s, "
+       TRACE_FIND("AVFormatReader::StreamCookie::FindKeyFrame(%ld,%s%s%s%s, "
                "%lld, %lld)\n", VirtualIndex(),
-               (flags & B_MEDIA_SEEK_TO_FRAME) ? "B_MEDIA_SEEK_TO_FRAME" : "",
-               (flags & B_MEDIA_SEEK_TO_TIME) ? "B_MEDIA_SEEK_TO_TIME" : "",
-               (flags & B_MEDIA_SEEK_CLOSEST_BACKWARD) ? 
"B_MEDIA_SEEK_CLOSEST_BACKWARD" : "",
-               (flags & B_MEDIA_SEEK_CLOSEST_FORWARD) ? 
"B_MEDIA_SEEK_CLOSEST_FORWARD" : "",
+               (flags & B_MEDIA_SEEK_TO_FRAME) ? " B_MEDIA_SEEK_TO_FRAME" : "",
+               (flags & B_MEDIA_SEEK_TO_TIME) ? " B_MEDIA_SEEK_TO_TIME" : "",
+               (flags & B_MEDIA_SEEK_CLOSEST_BACKWARD) ? " 
B_MEDIA_SEEK_CLOSEST_BACKWARD" : "",
+               (flags & B_MEDIA_SEEK_CLOSEST_FORWARD) ? " 
B_MEDIA_SEEK_CLOSEST_FORWARD" : "",
                *frame, *time);
 
        double frameRate = FrameRate();
        if ((flags & B_MEDIA_SEEK_TO_FRAME) != 0)
-               *time = (bigtime_t)(*frame * 1000000LL / frameRate);
+               *time = (bigtime_t)(*frame * 1000000LL / frameRate + 0.5);
 
        int64_t timeStamp = _ConvertToStreamTimeBase(*time);
 
-       TRACE_SEEK("  time: %.2fs -> %lld (time_base: %d/%d)\n", *time / 
1000000.0,
+       TRACE_FIND("  time: %.2fs -> %lld (time_base: %d/%d)\n", *time / 
1000000.0,
                timeStamp, fStream->time_base.num, fStream->time_base.den);
 
        int searchFlags = AVSEEK_FLAG_BACKWARD;
@@ -842,22 +913,32 @@
 
        int index = av_index_search_timestamp(fStream, timeStamp, searchFlags);
        if (index < 0) {
-               TRACE_SEEK("  av_index_search_timestamp() failed.\n");
-               // Just seek to the beginning of the stream and assume it is a
-               // keyframe...
-               *frame = 0;
-               *time = 0;
-               return B_OK;
+               TRACE_FIND("  av_index_search_timestamp() failed.\n");
+               // Best is to assume we can somehow seek to the time/frame
+               // and leave them as they are.
+       } else {
+               const AVIndexEntry& entry = fStream->index_entries[index];
+               timeStamp = entry.timestamp;
+               bigtime_t foundTime = _ConvertFromStreamTimeBase(timeStamp);
+               bigtime_t timeDiff = foundTime > *time
+                       ? foundTime - *time : *time - foundTime;
+       
+               if (fStreamBuildsIndexWhileReading && timeDiff > 1000000) {
+                       // If the stream is building the index on the fly while 
parsing
+                       // it, we only have entries in the index for positions 
already
+                       // decoded, i.e. we cannot seek into the future. In 
that case,
+                       // just assume that we can seek where we want and leave 
time/frame
+                       // unmodified.
+                       TRACE_FIND("  Not trusting generic index entry. "
+                               "(Current count: %d)\n", 
fStream->nb_index_entries);
+               } else
+                       *time = foundTime;
        }
-
-       const AVIndexEntry& entry = fStream->index_entries[index];
-       timeStamp = entry.timestamp;
-       *time = _ConvertFromStreamTimeBase(timeStamp);
-
-       TRACE_SEEK("  seeked time: %.2fs (%lld)\n", *time / 1000000.0, 
timeStamp);
+       
+       TRACE_FIND("  found time: %.2fs (%lld)\n", *time / 1000000.0, 
timeStamp);
        if ((flags & B_MEDIA_SEEK_TO_FRAME) != 0) {
-               *frame = *time * frameRate / 1000000LL;
-               TRACE_SEEK("  seeked frame: %lld\n", *frame);
+               *frame = *time * frameRate / 1000000LL + 0.5;
+               TRACE_FIND("  found frame: %lld\n", *frame);
        }
 
        return B_OK;


Other related posts:

  • » [haiku-commits] r38401 - haiku/trunk/src/add-ons/media/plugins/ffmpeg - superstippi