* Theoretically implemented seeking by bytes,
if the input format requires it. Practically, it does not work. * Implement the new meta-data API. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@38686 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -51,7 +51,7 @@ static const int64 kNoPTSValue = 0x8000000000000000LL;
|
||||
// INT64_C is not defined here.
|
||||
|
||||
|
||||
uint32
|
||||
static uint32
|
||||
avformat_to_beos_format(SampleFormat format)
|
||||
{
|
||||
switch (format) {
|
||||
@@ -67,13 +67,30 @@ avformat_to_beos_format(SampleFormat format)
|
||||
}
|
||||
|
||||
|
||||
uint32
|
||||
static uint32
|
||||
avformat_to_beos_byte_order(SampleFormat format)
|
||||
{
|
||||
// TODO: Huh?
|
||||
return B_MEDIA_HOST_ENDIAN;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
avmetadata_to_message(AVMetadata* metaData, BMessage* message)
|
||||
{
|
||||
if (metaData == NULL)
|
||||
return;
|
||||
|
||||
AVMetadataTag* tag = NULL;
|
||||
while ((tag = av_metadata_get(metaData, "", tag,
|
||||
AV_METADATA_IGNORE_SUFFIX))) {
|
||||
// TODO: Make sure we eventually follow a defined convention for
|
||||
// the names of meta-data keys.
|
||||
message->AddString(tag->key, tag->value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - AVFormatReader::StreamCookie
|
||||
|
||||
|
||||
@@ -98,10 +115,13 @@ public:
|
||||
inline int32 VirtualIndex() const
|
||||
{ return fVirtualIndex; }
|
||||
|
||||
status_t GetMetaData(BMessage* data);
|
||||
|
||||
inline const media_format& Format() const
|
||||
{ return fFormat; }
|
||||
|
||||
double FrameRate() const;
|
||||
bigtime_t Duration() const;
|
||||
|
||||
// Support for AVFormatReader
|
||||
status_t GetStreamInfo(int64* frameCount,
|
||||
@@ -159,6 +179,7 @@ private:
|
||||
media_format fFormat;
|
||||
|
||||
mutable bool fStreamBuildsIndexWhileReading;
|
||||
bool fSeekByBytes;
|
||||
};
|
||||
|
||||
|
||||
@@ -176,7 +197,8 @@ AVFormatReader::StreamCookie::StreamCookie(BPositionIO* source,
|
||||
|
||||
fReusePacket(false),
|
||||
|
||||
fStreamBuildsIndexWhileReading(false)
|
||||
fStreamBuildsIndexWhileReading(false),
|
||||
fSeekByBytes(false)
|
||||
{
|
||||
memset(&fFormat, 0, sizeof(media_format));
|
||||
av_new_packet(&fPacket, 0);
|
||||
@@ -231,9 +253,6 @@ AVFormatReader::StreamCookie::Open()
|
||||
(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.
|
||||
@@ -267,9 +286,13 @@ AVFormatReader::StreamCookie::Open()
|
||||
return B_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
fStreamBuildsIndexWhileReading
|
||||
= (inputFormat->flags & AVFMT_GENERIC_INDEX) != 0;
|
||||
fSeekByBytes = (inputFormat->flags & AVFMT_TS_DISCONT) != 0;
|
||||
|
||||
TRACE("AVFormatReader::StreamCookie::Open() - "
|
||||
"av_find_stream_info() success! Seek should be by bytes: %d\n",
|
||||
(inputFormat->flags & AVFMT_TS_DISCONT) != 0);
|
||||
"av_find_stream_info() success! Seeking by bytes: %d\n",
|
||||
fSeekByBytes);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
@@ -730,6 +753,15 @@ AVFormatReader::StreamCookie::StreamIndexFor(int32 virtualIndex) const
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
AVFormatReader::StreamCookie::GetMetaData(BMessage* data)
|
||||
{
|
||||
avmetadata_to_message(fStream->metadata, data);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
double
|
||||
AVFormatReader::StreamCookie::FrameRate() const
|
||||
{
|
||||
@@ -762,6 +794,23 @@ AVFormatReader::StreamCookie::FrameRate() const
|
||||
}
|
||||
|
||||
|
||||
bigtime_t
|
||||
AVFormatReader::StreamCookie::Duration() const
|
||||
{
|
||||
// TODO: This is 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
|
||||
// unfortunately, libavformat itself seems to set the time_base and
|
||||
// duration wrongly sometimes. :-(
|
||||
if ((int64)fStream->duration != kNoPTSValue)
|
||||
return _ConvertFromStreamTimeBase(fStream->duration);
|
||||
else if ((int64)fContext->duration != kNoPTSValue)
|
||||
return (bigtime_t)fContext->duration;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
AVFormatReader::StreamCookie::GetStreamInfo(int64* frameCount,
|
||||
bigtime_t* duration, media_format* format, const void** infoBuffer,
|
||||
@@ -782,24 +831,7 @@ AVFormatReader::StreamCookie::GetStreamInfo(int64* frameCount,
|
||||
}
|
||||
#endif // TRACE_AVFORMAT_READER
|
||||
|
||||
// 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
|
||||
// unfortunately, libavformat itself seems to set the time_base and
|
||||
// duration wrongly sometimes. :-(
|
||||
if ((int64)fStream->duration != kNoPTSValue) {
|
||||
*duration = _ConvertFromStreamTimeBase(fStream->duration);
|
||||
TRACE(" stream duration: %lld, time_base %.4f (%d/%d)\n",
|
||||
fStream->duration, av_q2d(fStream->time_base),
|
||||
fStream->time_base.num, fStream->time_base.den);
|
||||
} else if ((int64)fContext->duration != kNoPTSValue) {
|
||||
*duration = (bigtime_t)(1000000LL * fContext->duration / AV_TIME_BASE);
|
||||
TRACE(" stream duration: %lld (from AVFormatContext)\n",
|
||||
*duration);
|
||||
} else {
|
||||
*duration = 0;
|
||||
TRACE(" stream duration: N/A\n");
|
||||
}
|
||||
*duration = Duration();
|
||||
|
||||
TRACE(" duration: %lld or %.5fs\n", *duration, *duration / 1000000.0);
|
||||
|
||||
@@ -871,6 +903,8 @@ AVFormatReader::StreamCookie::Seek(uint32 flags, int64* frame,
|
||||
|
||||
int64_t timeStamp = *time;
|
||||
int64_t minTimeStamp = timeStamp - 1000000;
|
||||
if (minTimeStamp < 0)
|
||||
minTimeStamp = 0;
|
||||
int64_t maxTimeStamp = timeStamp + 1000000;
|
||||
|
||||
TRACE_SEEK(" time: %.5fs -> %lld, current DTS: %lld (time_base: %d/%d)\n",
|
||||
@@ -881,9 +915,24 @@ AVFormatReader::StreamCookie::Seek(uint32 flags, int64* frame,
|
||||
if ((flags & B_MEDIA_SEEK_CLOSEST_FORWARD) != 0)
|
||||
searchFlags = 0;
|
||||
|
||||
if (fSeekByBytes) {
|
||||
searchFlags |= AVSEEK_FLAG_BYTE;
|
||||
BAutolock _(fStreamLock);
|
||||
off_t fileSize;
|
||||
if (fSource->GetSize(&fileSize) != B_OK)
|
||||
return B_NOT_SUPPORTED;
|
||||
int64_t duration = Duration();
|
||||
if (duration == 0)
|
||||
return B_NOT_SUPPORTED;
|
||||
|
||||
timeStamp = fileSize * timeStamp / duration;
|
||||
minTimeStamp = INT64_MIN;
|
||||
maxTimeStamp = INT64_MAX;
|
||||
}
|
||||
|
||||
if (avformat_seek_file(fContext, -1, minTimeStamp, timeStamp,
|
||||
maxTimeStamp, searchFlags) < 0) {
|
||||
TRACE_SEEK(" avformat_seek_file() failed.\n");
|
||||
TRACE(" avformat_seek_file() failed.\n");
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
@@ -921,6 +970,9 @@ AVFormatReader::StreamCookie::FindKeyFrame(uint32 flags, int64* frame,
|
||||
(flags & B_MEDIA_SEEK_CLOSEST_FORWARD) ? " B_MEDIA_SEEK_CLOSEST_FORWARD" : "",
|
||||
*frame, *time);
|
||||
|
||||
if (fSeekByBytes)
|
||||
return B_OK;
|
||||
|
||||
double frameRate = FrameRate();
|
||||
if ((flags & B_MEDIA_SEEK_TO_FRAME) != 0)
|
||||
*time = (bigtime_t)(*frame * 1000000.0 / frameRate + 0.5);
|
||||
@@ -1347,6 +1399,43 @@ AVFormatReader::GetFileFormatInfo(media_file_format* mff)
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
AVFormatReader::GetMetaData(BMessage* _data)
|
||||
{
|
||||
// The first cookie is always there!
|
||||
const AVFormatContext* context = fStreams[0]->Context();
|
||||
|
||||
if (context == NULL)
|
||||
return B_NO_INIT;
|
||||
|
||||
avmetadata_to_message(context->metadata, _data);
|
||||
|
||||
// Add chapter info
|
||||
for (unsigned i = 0; i < context->nb_chapters; i++) {
|
||||
AVChapter* chapter = context->chapters[i];
|
||||
BMessage chapterData;
|
||||
chapterData.AddInt64("start", bigtime_t(1000000.0
|
||||
* chapter->start * chapter->time_base.num
|
||||
/ chapter->time_base.den + 0.5));
|
||||
chapterData.AddInt64("end", bigtime_t(1000000.0
|
||||
* chapter->end * chapter->time_base.num
|
||||
/ chapter->time_base.den + 0.5));
|
||||
|
||||
avmetadata_to_message(chapter->metadata, &chapterData);
|
||||
_data->AddMessage("be:chapter", &chapterData);
|
||||
}
|
||||
|
||||
// Add program info
|
||||
for (unsigned i = 0; i < context->nb_programs; i++) {
|
||||
BMessage progamData;
|
||||
avmetadata_to_message(context->programs[i]->metadata, &progamData);
|
||||
_data->AddMessage("be:program", &progamData);
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
@@ -1438,6 +1527,14 @@ AVFormatReader::GetStreamInfo(void* _cookie, int64* frameCount,
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
AVFormatReader::GetStreamMetaData(void* _cookie, BMessage* _data)
|
||||
{
|
||||
StreamCookie* cookie = reinterpret_cast<StreamCookie*>(_cookie);
|
||||
return cookie->GetMetaData(_data);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
AVFormatReader::Seek(void* _cookie, uint32 seekTo, int64* frame,
|
||||
bigtime_t* time)
|
||||
|
||||
@@ -21,6 +21,7 @@ public:
|
||||
virtual status_t Sniff(int32* streamCount);
|
||||
|
||||
virtual void GetFileFormatInfo(media_file_format* mff);
|
||||
virtual status_t GetMetaData(BMessage* _data);
|
||||
|
||||
virtual status_t AllocateCookie(int32 streamNumber,
|
||||
void** cookie);
|
||||
@@ -31,6 +32,9 @@ public:
|
||||
const void** infoBuffer,
|
||||
size_t* infoSize);
|
||||
|
||||
virtual status_t GetStreamMetaData(void* cookie,
|
||||
BMessage* _data);
|
||||
|
||||
virtual status_t Seek(void* cookie, uint32 flags, int64* frame,
|
||||
bigtime_t* time);
|
||||
virtual status_t FindKeyFrame(void* cookie, uint32 flags,
|
||||
|
||||
Reference in New Issue
Block a user