ffmpeg 3.3.3 APIを使用して、任意のフレームを取り込んでビデオを構築できるクラスをまとめようとしています。私はこの例を見ても良い例を見つけようと苦労していますが、例はまだ非難されている関数を使用しているようです。ヘッダーのドキュメントを使ってパッチを当てようとしています。新しいバージョン。私は出力に符号化されたパケットを書き込むためにav_interleaved_write_frameを使用する場合はav_interleaved_write_frameを使用していてもavio_writeを使用していない場合はmoov atom not foundが表示される
はその後ffprobeは、次の出力:
[mov,mp4,m4a,3gp,3g2,mj2 @ 0000000002760120] moov atom not found0
X:\Diagnostics.mp4: Invalid data found when processing input
ffplayは、このメソッドを使用して生成されたファイルを再生することができません。
私が代わりにavio_writeの呼び出しのためにそれを交換した場合、ffprobeではなく、出力:
Input #0, h264, from 'X:\Diagnostics.mp4':
Duration: N/A, bitrate: N/A
Stream #0:0: Video: h264 (Main), yuv420p(progressive), 672x380 [SAR 1:1 DAR 168:95], 25 fps, 25 tbr, 1200k tbn, 50 tbc
を、それは終わりに向かって迎えるまでに出力した場合ffplayはほとんどは、このファイルを再生することができます:
Input #0, h264, from 'X:\Diagnostics.mp4': 0KB sq= 0B f=0/0
Duration: N/A, bitrate: N/A
Stream #0:0: Video: h264 (Main), yuv420p(progressive), 672x380 [SAR 1:1 DAR 168:95], 25 fps, 25 tbr, 1200k tbn, 50 tbc
[h264 @ 000000000254ef80] error while decoding MB 31 22, bytestream -65
[h264 @ 000000000254ef80] concealing 102 DC, 102 AC, 102 MV errors in I frame
nan M-V: nan fd= 1 aq= 0KB vq= 0KB sq= 0B f=0/0
を
VLCはどちらの方法でもファイルを再生できません。第2の方法のファイルは、単一の黒いフレームを表示し、ビデオ出力を隠す。最初は何も表示されません。どちらもビデオ期間を与えません。
ここで何が起こっているのでしょうか?私は有効なフレームの良い塊を取得しているので、私の解決策は近いと思います。
コード:
void main()
{
OutputStream Stream("Output.mp4", 672, 380, 25, true);
Stream.Initialize();
int i = 100;
while(i--)
{
//... Generate a frame
Stream.WriteFrame(Frame);
}
Stream.CloseFile();
}
OutputStream::OutputStream(const std::string& Path, unsigned int Width, unsigned int Height, int Framerate, bool IsBGR)
: Stream()
, FrameIndex(0)
{
auto& ID = *m_InternalData;
ID.Path = Path;
ID.Width = Width;
ID.Height= Height;
ID.Framerate.num = Framerate;
ID.Framerate.den = 1;
ID.PixelFormat = IsBGR ? AV_PIX_FMT_BGR24 : AV_PIX_FMT_RGB24;
ID.CodecID = AV_CODEC_ID_H264;
ID.CodecTag = 0;
ID.AspectRatio.num = 1;
ID.AspectRatio.den = 1;
}
CameraStreamError OutputStream::Initialize()
{
av_log_set_callback(&InputStream::LogCallback);
av_register_all();
avformat_network_init();
auto& ID = *m_InternalData;
av_init_packet(&ID.Packet);
int Result = avformat_alloc_output_context2(&ID.FormatContext, nullptr, nullptr, ID.Path.c_str());
if(Result < 0 || !ID.FormatContext)
{
STREAM_ERROR(UnknownError);
}
AVCodec* Encoder = avcodec_find_encoder(ID.CodecID);
if(!Encoder)
{
STREAM_ERROR(NoH264Support);
}
AVStream* OutStream = avformat_new_stream(ID.FormatContext, Encoder);
if(!OutStream)
{
STREAM_ERROR(UnknownError);
}
ID.CodecContext = avcodec_alloc_context3(Encoder);
if(!ID.CodecContext)
{
STREAM_ERROR(NoH264Support);
}
ID.CodecContext->time_base = av_inv_q(ID.Framerate);
{
AVCodecParameters* CodecParams = OutStream->codecpar;
CodecParams->width = ID.Width;
CodecParams->height = ID.Height;
CodecParams->format = AV_PIX_FMT_YUV420P;
CodecParams->codec_id = ID.CodecID;
CodecParams->codec_type = AVMEDIA_TYPE_VIDEO;
CodecParams->profile = FF_PROFILE_H264_MAIN;
CodecParams->level = 40;
Result = avcodec_parameters_to_context(ID.CodecContext, CodecParams);
if(Result < 0)
{
STREAM_ERROR(EncoderCreationError);
}
}
if(ID.IsVideo)
{
ID.CodecContext->width = ID.Width;
ID.CodecContext->height = ID.Height;
ID.CodecContext->sample_aspect_ratio = ID.AspectRatio;
ID.CodecContext->time_base = av_inv_q(ID.Framerate);
if(Encoder->pix_fmts)
{
ID.CodecContext->pix_fmt = Encoder->pix_fmts[0];
}
else
{
ID.CodecContext->pix_fmt = ID.PixelFormat;
}
}
//Snip
Result = avcodec_open2(ID.CodecContext, Encoder, nullptr);
if(Result < 0)
{
STREAM_ERROR(EncoderCreationError);
}
Result = avcodec_parameters_from_context(OutStream->codecpar, ID.CodecContext);
if(Result < 0)
{
STREAM_ERROR(EncoderCreationError);
}
if(ID.FormatContext->oformat->flags & AVFMT_GLOBALHEADER)
{
ID.CodecContext->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
}
OutStream->time_base = ID.CodecContext->time_base;
OutStream->avg_frame_rate= av_inv_q(OutStream->time_base);
if(!(ID.FormatContext->oformat->flags & AVFMT_NOFILE))
{
Result = avio_open(&ID.FormatContext->pb, ID.Path.c_str(), AVIO_FLAG_WRITE);
if(Result < 0)
{
STREAM_ERROR(FileNotWriteable);
}
}
Result = avformat_write_header(ID.FormatContext, nullptr);
if(Result < 0)
{
STREAM_ERROR(WriteFailed);
}
ID.Output = std::make_unique<FFMPEG::Frame>(ID.CodecContext->width, ID.CodecContext->height, ID.CodecContext->pix_fmt);
ID.ConversionContext = sws_getCachedContext(
ID.ConversionContext,
ID.Width,
ID.Height,
ID.PixelFormat,
ID.CodecContext->width,
ID.CodecContext->height,
ID.CodecContext->pix_fmt,
SWS_BICUBIC,
NULL,
NULL,
NULL);
return CameraStreamError::Success;
}
CameraStreamError OutputStream::WriteFrame(FFMPEG::Frame* Frame)
{
auto& ID = *m_InternalData;
ID.Output->Prepare();
int OutputSliceSize = sws_scale(m_InternalData->ConversionContext, Frame->GetFrame()->data, Frame->GetFrame()->linesize, 0, Frame->GetHeight(), ID.Output->GetFrame()->data, ID.Output->GetFrame()->linesize);
ID.Output->GetFrame()->pts = ID.CodecContext->frame_number;
int Result = avcodec_send_frame(GetData().CodecContext, ID.Output->GetFrame());
if(Result == AVERROR(EAGAIN))
{
CameraStreamError ResultErr = SendAll();
if(ResultErr != CameraStreamError::Success)
{
return ResultErr;
}
Result = avcodec_send_frame(GetData().CodecContext, ID.Output->GetFrame());
}
if(Result == 0)
{
CameraStreamError ResultErr = SendAll();
if(ResultErr != CameraStreamError::Success)
{
return ResultErr;
}
}
FrameIndex++;
return CameraStreamError::Success;
}
CameraStreamError OutputStream::SendAll(void)
{
auto& ID = *m_InternalData;
int Result;
do
{
AVPacket TempPacket = {};
av_init_packet(&TempPacket);
Result = avcodec_receive_packet(GetData().CodecContext, &TempPacket);
if(Result == 0)
{
av_packet_rescale_ts(&TempPacket, ID.CodecContext->time_base, ID.FormatContext->streams[0]->time_base);
TempPacket.stream_index = ID.FormatContext->streams[0]->index;
//avio_write(ID.FormatContext->pb, TempPacket.data, TempPacket.size);
Result = av_interleaved_write_frame(ID.FormatContext, &TempPacket);
if(Result < 0)
{
STREAM_ERROR(WriteFailed);
}
av_packet_unref(&TempPacket);
}
else if(Result != AVERROR(EAGAIN))
{
continue;
}
else if(Result != AVERROR_EOF)
{
break;
}
else if(Result < 0)
{
STREAM_ERROR(WriteFailed);
}
} while (Result == 0);
return CameraStreamError::Success;
}
CameraStreamError OutputStream::CloseFile()
{
auto& ID = *m_InternalData;
while(true)
{
//Flush
int Result = avcodec_send_frame(ID.CodecContext, nullptr);
if(Result == 0)
{
CameraStreamError StrError = SendAll();
if(StrError != CameraStreamError::Success)
{
return StrError;
}
}
else if(Result == AVERROR_EOF)
{
break;
}
else
{
STREAM_ERROR(WriteFailed);
}
}
int Result = av_write_trailer(ID.FormatContext);
if(Result < 0)
{
STREAM_ERROR(WriteFailed);
}
if(!(ID.FormatContext->oformat->flags& AVFMT_NOFILE))
{
Result = avio_close(ID.FormatContext->pb);
if(Result < 0)
{
STREAM_ERROR(WriteFailed);
}
}
return CameraStreamError::Success;
}
注意私はいくつかのことを簡素化し、他の場所だった数ビットをインライン化しました。私はまた、ファイルが閉じられた後に起こる何かが無関係なので、すべてのシャットダウンコードを削除しました。
完全レポここに:https://github.com/IanNorris/Witnessこれを複製すると、問題は「診断」出力にあり、出力ファイルは問題ありません。 Xには2つのハードコードされたパスがあります。
ありがとうございます!私は実際にこれらのコードを持っていましたが、あなたの答えは、それが呼び出されたことを確認させました。それは両方のファイルではなく、最初のファイルのみでした。これは、消失したデストラクタが原因です。今は期待どおりに動作します。 – icStatic