FFMPEG Plugin: Fix playing video files.
- This should fix the bug where video files that played well before the recent changes to the FFMPEG Plugin didn't play anymore. Now we apply the essential video container properties (that were passed by with Setup()) to the AVCodecContext. Some video formats simply store those properties in the container only (e.g. AVI, WMV) and not in the video frames itself (e.g. MPEG2). Tested with several files from samples.ffmpeg.org and from the FATE suite of FFMPEG.
This commit is contained in:
parent
d78faaaf70
commit
75bd62e868
@ -443,6 +443,14 @@ AVCodecDecoder::_NegotiateVideoOutputFormat(media_format* inOutFormat)
|
||||
TRACE(" requested video format 0x%x\n",
|
||||
inOutFormat->u.raw_video.display.format);
|
||||
|
||||
_ApplyEssentialVideoContainerPropertiesToContext();
|
||||
// This makes video formats play that encode the video properties in
|
||||
// the video container (e.g. WMV) and not in the video frames
|
||||
// themself (e.g. MPEG2).
|
||||
// Note: Doing this step everytime is OK, because the first call to
|
||||
// _DecodeNextVideoFrame() will update the essential video format
|
||||
// properties accordingly.
|
||||
|
||||
// Make MediaPlayer happy (if not in rgb32 screen depth and no overlay,
|
||||
// it will only ask for YCbCr, which DrawBitmap doesn't handle, so the
|
||||
// default colordepth is RGB32).
|
||||
@ -822,6 +830,44 @@ AVCodecDecoder::_DecodeNextVideoFrame()
|
||||
}
|
||||
|
||||
|
||||
/*! \brief Applies all essential video input properties from fInputFormat to
|
||||
fContext.
|
||||
|
||||
Note: This function must be called before the AVCodec is opened via
|
||||
avcodec_open2(). Otherwise the behaviour of FFMPEG's video decoding
|
||||
function avcodec_decode_video2() is undefined.
|
||||
|
||||
Essential properties applied:
|
||||
- display.line_width copied to fContext->width
|
||||
- display.line_count copied to fContext->height
|
||||
- pixel_width_aspect and pixel_height_aspect converted to
|
||||
fContext->sample_aspect_ratio
|
||||
- field_rate converted to fContext->time_base and
|
||||
fContext->ticks_per_frame
|
||||
*/
|
||||
void
|
||||
AVCodecDecoder::_ApplyEssentialVideoContainerPropertiesToContext()
|
||||
{
|
||||
media_raw_video_format containerProperties
|
||||
= fInputFormat.u.encoded_video.output;
|
||||
|
||||
fContext->width = containerProperties.display.line_width;
|
||||
fContext->height = containerProperties.display.line_count;
|
||||
|
||||
if (containerProperties.pixel_width_aspect > 0
|
||||
&& containerProperties.pixel_height_aspect > 0) {
|
||||
ConvertVideoAspectWidthAndHeightToAVCodecContext(
|
||||
containerProperties.pixel_width_aspect,
|
||||
containerProperties.pixel_height_aspect, *fContext);
|
||||
}
|
||||
|
||||
if (containerProperties.field_rate > 0.0) {
|
||||
ConvertVideoFrameRateToAVCodecContext(containerProperties.field_rate,
|
||||
*fContext);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*! \brief Loads the next video chunk into fVideoChunkBuffer and assigns it
|
||||
(including the start time) to fTempPacket accordingly only if
|
||||
fTempPacket is empty.
|
||||
|
@ -61,6 +61,7 @@ private:
|
||||
media_header* mediaHeader,
|
||||
media_decode_info* info);
|
||||
status_t _DecodeNextVideoFrame();
|
||||
void _ApplyEssentialVideoContainerPropertiesToContext();
|
||||
status_t _LoadNextVideoChunkIfNeededAndAssignStartTime();
|
||||
// TODO: Remove the "Video" word once
|
||||
// the audio path is responsible for
|
||||
|
@ -24,6 +24,9 @@ extern "C" {
|
||||
/*! \brief Converts FFmpeg notation of video aspect ratio into the Media Kits
|
||||
notation.
|
||||
|
||||
\see ConvertVideoAspectWidthAndHeightToAVCodecContext() for converting in
|
||||
the other direction.
|
||||
|
||||
\param contextIn An AVCodeContext structure of FFmpeg containing the values
|
||||
needed to calculate the Media Kit video aspect ratio.
|
||||
The following fields are used for the calculation:
|
||||
@ -72,6 +75,57 @@ ConvertAVCodecContextToVideoAspectWidthAndHeight(AVCodecContext& contextIn,
|
||||
}
|
||||
|
||||
|
||||
/*! \brief Converts the Media Kits notation of video aspect ratio into FFmpegs
|
||||
notation.
|
||||
|
||||
\see ConvertAVCodecContextToVideoAspectWidthAndHeight() for converting in
|
||||
the other direction.
|
||||
|
||||
\param pixelWidthAspectIn Contains Media Kits notation of the video aspect
|
||||
ratio width. E.g. 16:9 -> 16 is passed here.
|
||||
\param pixelHeightAspectIn Contains Media Kits notation of the video aspect
|
||||
ratio height. E.g. 16:9 -> 9 is passed here.
|
||||
\param contextInOut An AVCodecContext structure of FFmpeg.
|
||||
On input must contain the following fields already initialized
|
||||
otherwise the behaviour is undefined:
|
||||
- AVCodecContext.width (must)
|
||||
- AVCodecContext.height (must)
|
||||
On output contains converted values in the following fields (other
|
||||
fields stay as they were on input):
|
||||
- AVCodecContext.sample_aspect_ratio.num
|
||||
- AVCodecContext.sample_aspect_ratio.den
|
||||
*/
|
||||
inline void
|
||||
ConvertVideoAspectWidthAndHeightToAVCodecContext(uint16 pixelWidthAspectIn,
|
||||
uint16 pixelHeightAspectIn, AVCodecContext& contextInOut)
|
||||
{
|
||||
assert(pixelWidthAspectIn > 0);
|
||||
assert(pixelHeightAspectIn > 0);
|
||||
assert(contextInOut.width > 0);
|
||||
assert(contextInOut.height > 0);
|
||||
|
||||
AVRational pureVideoDimensionAspectRatio;
|
||||
av_reduce(&pureVideoDimensionAspectRatio.num,
|
||||
&pureVideoDimensionAspectRatio.den, contextInOut.width,
|
||||
contextInOut.height, 1024 * 1024);
|
||||
|
||||
if (pureVideoDimensionAspectRatio.num == pixelWidthAspectIn
|
||||
&& pureVideoDimensionAspectRatio.den == pixelHeightAspectIn) {
|
||||
// The passed Media Kit pixel aspect ratio equals the video dimension
|
||||
// aspect ratio. Set sample_aspect_ratio to "ignore".
|
||||
contextInOut.sample_aspect_ratio.num = 0;
|
||||
contextInOut.sample_aspect_ratio.den = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
av_reduce(&contextInOut.sample_aspect_ratio.num,
|
||||
&contextInOut.sample_aspect_ratio.den,
|
||||
contextInOut.height * pixelWidthAspectIn,
|
||||
contextInOut.width * pixelHeightAspectIn,
|
||||
1024 * 1024);
|
||||
}
|
||||
|
||||
|
||||
/*! \brief Calculates bytes per row for a video frame.
|
||||
|
||||
\param colorSpace The Media Kit color space the video frame uses.
|
||||
@ -108,6 +162,9 @@ CalculateBytesPerRowWithColorSpaceAndVideoWidth(color_space colorSpace, int vide
|
||||
/*! \brief Converts FFmpeg notation of video frame rate into the Media Kits
|
||||
notation.
|
||||
|
||||
\see ConvertAVCodecContextToVideoFrameRate() for converting in the other
|
||||
direction.
|
||||
|
||||
\param contextIn An AVCodeContext structure of FFmpeg containing the values
|
||||
needed to calculate the Media Kit video frame rate.
|
||||
The following fields are used for the calculation:
|
||||
@ -134,4 +191,31 @@ ConvertAVCodecContextToVideoFrameRate(AVCodecContext& contextIn, float& frameRat
|
||||
= possiblyInterlacedFrameRate / numberOfInterlacedFramesPerFullFrame;
|
||||
}
|
||||
|
||||
|
||||
/*! \brief Converts the Media Kits notation of video frame rate to FFmpegs
|
||||
notation.
|
||||
|
||||
\see ConvertAVCodecContextToVideoFrameRate() for converting in the other
|
||||
direction.
|
||||
|
||||
\param frameRateIn Contains Media Kits notation of the video frame rate
|
||||
that will be converted into FFmpegs notation. Must be greater than
|
||||
zero.
|
||||
\param contextOut An AVCodecContext structure of FFmpeg.
|
||||
On output contains converted values in the following fields (other
|
||||
fields stay as they were on input):
|
||||
- AVCodecContext.time_base.num
|
||||
- AVCodecContext.time_base.den
|
||||
- AVCodecContext.ticks_per_frame is set to 1
|
||||
*/
|
||||
inline void
|
||||
ConvertVideoFrameRateToAVCodecContext(float frameRateIn,
|
||||
AVCodecContext& contextOut)
|
||||
{
|
||||
assert(frameRateIn > 0);
|
||||
|
||||
contextOut.ticks_per_frame = 1;
|
||||
contextOut.time_base = av_d2q(1.0 / frameRateIn, 1024);
|
||||
}
|
||||
|
||||
#endif // UTILITIES_H
|
||||
|
Loading…
x
Reference in New Issue
Block a user