AVFormatWriter: Move codec to codecpar

* Little cleanup included.
This commit is contained in:
Barrett17
2018-08-04 12:11:09 +02:00
parent 6283eeb2ff
commit 428d87c581
2 changed files with 79 additions and 55 deletions
@@ -1,5 +1,6 @@
/*
* Copyright 2009-2010, Stephan Aßmus <[email protected]>
* Copyright 2018, Dario Casalinuovo
* All rights reserved. Distributed under the terms of the GNU L-GPL license.
*/
@@ -118,30 +119,22 @@ AVFormatWriter::StreamCookie::Init(media_format* format,
return B_ERROR;
}
// TRACE(" fStream->codec: %p\n", fStream->codec);
// TRACE(" fStream->codecpar: %p\n", fStream->codecpar);
// TODO: This is a hack for now! Use avcodec_find_encoder_by_name()
// or something similar...
fStream->codec->codec_id = (CodecID)codecInfo->sub_id;
if (fStream->codec->codec_id == AV_CODEC_ID_NONE)
fStream->codec->codec_id = raw_audio_codec_id_for(*format);
fStream->codecpar->codec_id = (CodecID)codecInfo->sub_id;
if (fStream->codecpar->codec_id == AV_CODEC_ID_NONE)
fStream->codecpar->codec_id = raw_audio_codec_id_for(*format);
// Setup the stream according to the media format...
if (format->type == B_MEDIA_RAW_VIDEO) {
fStream->codec->codec_type = AVMEDIA_TYPE_VIDEO;
#if GET_CONTEXT_DEFAULTS
// NOTE: API example does not do this:
avcodec_get_context_defaults(fStream->codec);
#endif
// frame rate
fStream->codec->time_base.den = (int)format->u.raw_video.field_rate;
fStream->codec->time_base.num = 1;
fStream->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
fStream->time_base.den = (int)format->u.raw_video.field_rate;
fStream->time_base.num = 1;
// video size
fStream->codec->width = format->u.raw_video.display.line_width;
fStream->codec->height = format->u.raw_video.display.line_count;
fStream->codecpar->width = format->u.raw_video.display.line_width;
fStream->codecpar->height = format->u.raw_video.display.line_count;
// pixel aspect ratio
fStream->sample_aspect_ratio.num
= format->u.raw_video.pixel_width_aspect;
@@ -150,51 +143,46 @@ AVFormatWriter::StreamCookie::Init(media_format* format,
if (fStream->sample_aspect_ratio.num == 0
|| fStream->sample_aspect_ratio.den == 0) {
av_reduce(&fStream->sample_aspect_ratio.num,
&fStream->sample_aspect_ratio.den, fStream->codec->width,
fStream->codec->height, 255);
&fStream->sample_aspect_ratio.den, fStream->codecpar->width,
fStream->codecpar->height, 255);
}
fStream->codec->gop_size = 12;
fStream->codec->sample_aspect_ratio = fStream->sample_aspect_ratio;
fStream->codecpar->sample_aspect_ratio = fStream->sample_aspect_ratio;
// Use the last supported pixel format of the AVCodec, which we hope
// is the one with the best quality (true for all currently supported
// encoders).
// AVCodec* codec = fStream->codec->codec;
// AVCodec* codec = fStream->codecpar->codec;
// for (int i = 0; codec->pix_fmts[i] != PIX_FMT_NONE; i++)
// fStream->codec->pix_fmt = codec->pix_fmts[i];
fStream->codec->pix_fmt = AV_PIX_FMT_YUV420P;
// fStream->codecpar->pix_fmt = codec->pix_fmts[i];
fStream->codecpar->format = AV_PIX_FMT_YUV420P;
} else if (format->type == B_MEDIA_RAW_AUDIO) {
fStream->codec->codec_type = AVMEDIA_TYPE_AUDIO;
#if GET_CONTEXT_DEFAULTS
// NOTE: API example does not do this:
avcodec_get_context_defaults(fStream->codec);
#endif
fStream->codecpar->codec_type = AVMEDIA_TYPE_AUDIO;
// frame rate
fStream->codec->sample_rate = (int)format->u.raw_audio.frame_rate;
fStream->codecpar->sample_rate = (int)format->u.raw_audio.frame_rate;
// channels
fStream->codec->channels = format->u.raw_audio.channel_count;
fStream->codecpar->channels = format->u.raw_audio.channel_count;
// set fStream to the audio format we want to use. This is only a hint
// (each encoder has a different set of accepted formats)
switch (format->u.raw_audio.format) {
case media_raw_audio_format::B_AUDIO_FLOAT:
fStream->codec->sample_fmt = AV_SAMPLE_FMT_FLT;
fStream->codecpar->format = AV_SAMPLE_FMT_FLT;
break;
case media_raw_audio_format::B_AUDIO_DOUBLE:
fStream->codec->sample_fmt = AV_SAMPLE_FMT_DBL;
fStream->codecpar->format = AV_SAMPLE_FMT_DBL;
break;
case media_raw_audio_format::B_AUDIO_INT:
fStream->codec->sample_fmt = AV_SAMPLE_FMT_S32;
fStream->codecpar->format = AV_SAMPLE_FMT_S32;
break;
case media_raw_audio_format::B_AUDIO_SHORT:
fStream->codec->sample_fmt = AV_SAMPLE_FMT_S16;
fStream->codecpar->format = AV_SAMPLE_FMT_S16;
break;
case media_raw_audio_format::B_AUDIO_UCHAR:
fStream->codec->sample_fmt = AV_SAMPLE_FMT_U8;
fStream->codecpar->format = AV_SAMPLE_FMT_U8;
break;
case media_raw_audio_format::B_AUDIO_CHAR:
@@ -205,24 +193,24 @@ AVFormatWriter::StreamCookie::Init(media_format* format,
// Now negociate the actual format with the encoder
// First check if the requested format is acceptable
AVCodec* codec = avcodec_find_encoder(fStream->codec->codec_id);
AVCodec* codec = avcodec_find_encoder(fStream->codecpar->codec_id);
if (codec == NULL)
return B_MEDIA_BAD_FORMAT;
const enum AVSampleFormat *p = codec->sample_fmts;
for (; *p != -1; p++) {
if (*p == fStream->codec->sample_fmt)
if (*p == fStream->codecpar->format)
break;
}
// If not, force one of the acceptable ones
if (*p == -1) {
fStream->codec->sample_fmt = codec->sample_fmts[0];
fStream->codecpar->format = codec->sample_fmts[0];
// And finally set the format struct to the accepted format. It is
// then up to the caller to make sure we get data matching that
// format.
switch (fStream->codec->sample_fmt) {
switch (fStream->codecpar->format) {
case AV_SAMPLE_FMT_FLT:
format->u.raw_audio.format
= media_raw_audio_format::B_AUDIO_FLOAT;
@@ -254,43 +242,39 @@ AVFormatWriter::StreamCookie::Init(media_format* format,
switch (format->u.raw_audio.channel_count) {
default:
case 2:
fStream->codec->channel_layout = AV_CH_LAYOUT_STEREO;
fStream->codecpar->channel_layout = AV_CH_LAYOUT_STEREO;
break;
case 1:
fStream->codec->channel_layout = AV_CH_LAYOUT_MONO;
fStream->codecpar->channel_layout = AV_CH_LAYOUT_MONO;
break;
case 3:
fStream->codec->channel_layout = AV_CH_LAYOUT_SURROUND;
fStream->codecpar->channel_layout = AV_CH_LAYOUT_SURROUND;
break;
case 4:
fStream->codec->channel_layout = AV_CH_LAYOUT_QUAD;
fStream->codecpar->channel_layout = AV_CH_LAYOUT_QUAD;
break;
case 5:
fStream->codec->channel_layout = AV_CH_LAYOUT_5POINT0;
fStream->codecpar->channel_layout = AV_CH_LAYOUT_5POINT0;
break;
case 6:
fStream->codec->channel_layout = AV_CH_LAYOUT_5POINT1;
fStream->codecpar->channel_layout = AV_CH_LAYOUT_5POINT1;
break;
case 8:
fStream->codec->channel_layout = AV_CH_LAYOUT_7POINT1;
fStream->codecpar->channel_layout = AV_CH_LAYOUT_7POINT1;
break;
case 10:
fStream->codec->channel_layout = AV_CH_LAYOUT_7POINT1_WIDE;
fStream->codecpar->channel_layout = AV_CH_LAYOUT_7POINT1_WIDE;
break;
}
} else {
// The bits match 1:1 for media_multi_channels and FFmpeg defines.
fStream->codec->channel_layout = format->u.raw_audio.channel_mask;
fStream->codecpar->channel_layout = format->u.raw_audio.channel_mask;
}
}
// Some formats want stream headers to be separate
if ((fContext->oformat->flags & AVFMT_GLOBALHEADER) != 0)
fStream->codec->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
TRACE(" stream->time_base: (%d/%d), codec->time_base: (%d/%d))\n",
fStream->time_base.num, fStream->time_base.den,
fStream->codec->time_base.num, fStream->codec->time_base.den);
fStream->codecpar->time_base.num, fStream->codecpar->time_base.den);
#if 0
// Write the AVCodecContext pointer to the user data section of the
@@ -337,7 +321,7 @@ AVFormatWriter::StreamCookie::WriteChunk(const void* chunkBuffer,
TRACE_PACKET(" PTS: %lld (stream->time_base: (%d/%d), "
"codec->time_base: (%d/%d))\n", fPacket.pts,
fStream->time_base.num, fStream->time_base.den,
fStream->codec->time_base.num, fStream->codec->time_base.den);
fStream->codecpar->time_base.num, fStream->codecpar->time_base.den);
#if 0
// TODO: Eventually, we need to write interleaved packets, but
@@ -395,10 +379,13 @@ AVFormatWriter::~AVFormatWriter()
#if OPEN_CODEC_CONTEXT
// We only need to close the AVCodecContext when we opened it.
// This is experimental, see CommitHeader().
// NOTE: Since the introduction of AVCodecParameters
// I am not sure this logic is correct.
if (fCodecOpened)
avcodec_close(fContext->streams[i]->codec);
#endif
av_freep(&fContext->streams[i]->codec);
av_freep(&fContext->streams[i]->codecpar);
av_freep(&fContext->streams[i]);
}
@@ -1,6 +1,7 @@
/*
* Copyright 2009, Stephan Aßmus <[email protected]>
* Copyright 2014, Colin Günther <[email protected]>
* Copyright 2018, Dario Casalinuovo
* All rights reserved. Distributed under the terms of the GNU L-GPL license.
*/
#ifndef UTILITIES_H
@@ -75,6 +76,42 @@ ConvertAVCodecContextToVideoAspectWidthAndHeight(AVCodecContext& contextIn,
}
inline void
ConvertAVCodecParametersToVideoAspectWidthAndHeight(AVCodecParameters& parametersIn,
uint16& pixelWidthAspectOut, uint16& pixelHeightAspectOut)
{
assert(parametersIn.sample_aspect_ratio.num >= 0);
assert(parametersIn.width > 0);
assert(parametersIn.height > 0);
// The following code is based on code originally located in
// AVFormatReader::Stream::Init() and thus should be copyrighted to Stephan
// Aßmus
AVRational pixelAspectRatio;
if (parametersIn.sample_aspect_ratio.num == 0
|| parametersIn.sample_aspect_ratio.den == 0) {
// AVCodecContext doesn't contain a video aspect ratio, so calculate it
// ourselve based solely on the video dimensions
av_reduce(&pixelAspectRatio.num, &pixelAspectRatio.den, parametersIn.width,
parametersIn.height, 1024 * 1024);
pixelWidthAspectOut = static_cast<int16>(pixelAspectRatio.num);
pixelHeightAspectOut = static_cast<int16>(pixelAspectRatio.den);
return;
}
// AVCodecContext contains a video aspect ratio, so use it
av_reduce(&pixelAspectRatio.num, &pixelAspectRatio.den,
parametersIn.width * parametersIn.sample_aspect_ratio.num,
parametersIn.height * parametersIn.sample_aspect_ratio.den,
1024 * 1024);
pixelWidthAspectOut = static_cast<int16>(pixelAspectRatio.num);
pixelHeightAspectOut = static_cast<int16>(pixelAspectRatio.den);
}
/*! \brief Converts the Media Kits notation of video aspect ratio into FFmpegs
notation.