media/ffmpeg: Pass most packet metadata to decoder.

While AVPacket itself contains other fields, the
important ones are all static, and fit in 64 bytes.
So we can put them into the chunk media header directly
and then grab them again in AVCodecDecoder.

With that passed through, we can then use the
best_effort_timestamp, as it's more likely to be
correct.

Change-Id: Ied82137694f1307d4dcb177f3f9a7cb6b798461a
Reviewed-on: https://review.haiku-os.org/c/haiku/+/7525
Reviewed-by: waddlesplash <waddlesplash@gmail.com>
This commit is contained in:
Augustin Cavalier 2024-03-14 16:09:18 -04:00 committed by waddlesplash
parent 6c05cfc094
commit 45bd581b70
3 changed files with 40 additions and 19 deletions

View File

@ -1402,26 +1402,23 @@ AVCodecDecoder::_LoadNextChunkIfNeededAndAssignStartTime()
fTempPacket->data = fChunkBuffer;
fTempPacket->size = fChunkBufferSize;
fTempPacket->dts = chunkMediaHeader.start_time;
// Let FFMPEG handle the correct relationship between start_time and
// decoded a/v frame. By doing so we are simply copying the way how it
// is implemented in ffplay.c for video frames (for audio frames it
// works, too, but isn't used by ffplay.c).
// \see http://git.videolan.org/?p=ffmpeg.git;a=blob;f=ffplay.c;h=09623db374e5289ed20b7cc28c262c4375a8b2e4;hb=9153b33a742c4e2a85ff6230aea0e75f5a8b26c2#l1502
//
// FIXME: Research how to establish a meaningful relationship between
// start_time and decoded a/v frame when the received chunk buffer
// contains partial a/v frames. Maybe some data formats do contain time
// stamps (ake pts / dts fields) that can be evaluated by FFMPEG. But
// as long as I don't have such video data to test it, it makes no
// sense trying to implement it.
//
// FIXME: Implement tracking start_time of video frames originating in
// data chunks that encode more than one video frame at a time. In that
// case on would increment the start_time for each consecutive frame of
// such a data chunk (like it is done for audio frame decoding). But as
// long as I don't have such video data to test it, it makes no sense
// to implement it.
if (chunkMediaHeader.user_data_type == AVPACKET_USER_DATA_TYPE) {
avpacket_user_data* data = (avpacket_user_data*)&chunkMediaHeader.user_data;
fTempPacket->pts = data->pts;
fTempPacket->dts = data->dts;
fTempPacket->stream_index = data->stream_index;
fTempPacket->flags = data->flags;
fTempPacket->duration = data->duration;
fTempPacket->pos = data->pos;
}
#ifdef LOG_STREAM_TO_FILE
BFile* logFile = fIsAudio ? &sAudioStreamLogFile : &sVideoStreamLogFile;
@ -1576,9 +1573,7 @@ AVCodecDecoder::_UpdateMediaHeaderForVideoFrame()
fHeader.type = B_MEDIA_RAW_VIDEO;
fHeader.file_pos = 0;
fHeader.orig_size = 0;
fHeader.start_time = fRawDecodedPicture->pkt_dts;
// The pkt_dts is already in microseconds, even if ffmpeg docs says
// 'in codec time_base units'
fHeader.start_time = fRawDecodedPicture->best_effort_timestamp;
fHeader.size_used = av_image_get_buffer_size(
colorspace_to_pixfmt(fOutputColorSpace), fRawDecodedPicture->width,
fRawDecodedPicture->height, 1);

View File

@ -693,6 +693,19 @@ StreamBase::GetNextChunk(const void** chunkBuffer,
*chunkSize = fPacket.size;
if (mediaHeader != NULL) {
#if __GNUC__ != 2
static_assert(sizeof(avpacket_user_data) <= sizeof(mediaHeader->user_data),
"avpacket user data too large");
#endif
mediaHeader->user_data_type = AVPACKET_USER_DATA_TYPE;
avpacket_user_data* data = (avpacket_user_data*)mediaHeader->user_data;
data->pts = fPacket.pts;
data->dts = fPacket.dts;
data->stream_index = fPacket.stream_index;
data->flags = fPacket.flags;
data->duration = fPacket.duration;
data->pos = fPacket.pos;
mediaHeader->type = fFormat.type;
mediaHeader->buffer = 0;
mediaHeader->destination = -1;

View File

@ -23,6 +23,19 @@ extern "C" {
}
/*! \brief Structure used for passing AVPacket metadata through media_header::user_data. */
struct avpacket_user_data {
int64_t pts;
int64_t dts;
int stream_index;
int flags;
int64_t duration;
int64_t pos;
};
#define AVPACKET_USER_DATA_TYPE 'ffav'
/*! \brief Converts FFmpeg notation of video aspect ratio into the Media Kits
notation.
@ -62,7 +75,7 @@ ConvertAVCodecContextToVideoAspectWidthAndHeight(AVCodecContext& contextIn,
// ourselve based solely on the video dimensions
av_reduce(&pixelAspectRatio.num, &pixelAspectRatio.den, contextIn.width,
contextIn.height, 1024 * 1024);
pixelWidthAspectOut = static_cast<int16>(pixelAspectRatio.num);
pixelHeightAspectOut = static_cast<int16>(pixelAspectRatio.den);
return;
@ -210,7 +223,7 @@ CalculateBytesPerRowWithColorSpaceAndVideoWidth(color_space colorSpace, int vide
/*! \brief Converts the Media Kits notation of video frame rate to FFmpegs
notation.
\see ConvertAVCodecContextToVideoFrameRate() for converting in the other
direction.