我尝试使用FFMPeg解码H264原始流。
我已收到已保存的视频,并使用以下命令进入FFMpeg:
ffmpeg -i 20161201-090322.264 -pixel_format yuv420p -filter:v fps=fps=600/60 $filename%03d.raw
成功获取视频中的帧。 然后,我开始尝试解码直接流(这些视频中保存的确切内容)。
我正在这样初始化ffmpeg:
cam->ffmpegCodec = avcodec_find_decoder(AV_CODEC_ID_H264);
cam->ffmpgContext = avcodec_alloc_context3(cam->ffmpegCodec);
cam->ffmpgContext->width = cam->Width;
cam->ffmpgContext->height = cam->Height;
cam->ffmpgContext->pix_fmt = AV_PIX_FMT_YUV420P;
cam->ffmpegFrame = av_frame_alloc();
cam->ffmpegParser = av_parser_init(AV_CODEC_ID_H264);
if(!cam->ffmpegParser)
{
sprintf(msg, "Error, initializing parser");
libLogCtx(msg, MODULE_NAME, PLogFileRelease, true);
}
int res = avcodec_open2(cam->ffmpgContext, cam->ffmpegCodec, 0);
if( res != 0)
{
sprintf(msg, "Error, openning codec [%d]", res);
libLogCtx(msg, MODULE_NAME, PLogFileRelease, true);
}
而这些是我在凸轮结构中的声明:
AVCodecContext *ffmpgContext;
AVCodec *ffmpegCodec;
AVFrame *ffmpegFrame;
AVCodecParserContext *ffmpegParser;
当我收到流内容时,我会执行以下步骤:
/// Copy the received data to buffer
memcpy(cam->imageBuffer + cam->imageBufferSz, pBuffer, dwBufSize);
cam->imageBufferSz += dwBufSize;
/// If there's some data,
if(cam->imageBufferSz > 0)
{
/// Try to parse
uint8_t* data = NULL;
int size = 0;
int len = av_parser_parse2(cam->ffmpegParser, cam->ffmpgContext, &data, &size,
cam->imageBuffer, cam->imageBufferSz, 0, 0, AV_NOPTS_VALUE);
if(size > 0 && len >= 0)
{
/// Fill the packet and decode
AVPacket pkt;
av_init_packet(&pkt);
pkt.data = cam->imageBuffer;
pkt.size = cam->imageBufferSz;
int frameFinished = 0;
int nres = avcodec_decode_video2(cam->ffmpgContext, cam->ffmpegFrame, &frameFinished, &pkt);
/// If decoding was successfully, Save only the Y to file (i'm just testing).
if(frameFinished)
{
char fnm[255];
sprintf(fnm, "C:\\Users\\Black_Spiders\\Desktop\\Rls\\test%d.raw", n);
n++;
FILE* f = (FILE*)fopen(fnm, "w");
for (int y = 0; y < cam->ffmpegFrame->height; y++)
{
fwrite(cam->ffmpegFrame->data[0] + y*cam->ffmpegFrame->linesize[0], 1, cam->ffmpegFrame->width, f);
}
fclose(f);
}
}
}
虽然我的代码看起来还不错(在互联网上有一段时间了),但我有这样的结果:
有人可以给我任何建议吗?
最诚挚的问候,
答案 0 :(得分:0)
以下是直接来自ffmpeg文档的示例代码:
while(in_len) {
len = av_parser_parse2(myparser, AVCodecContext, &data, &size,
in_data, in_len,
pts, dts, pos);
in_data += len;
in_len -= len;
if(size)
decode_frame(data, size);
}
所以,想法是调用这个函数,它将返回:
1)指向编码帧的指针和大小以传递给解码器;注意在你指出的例子中使用大小(但他们没有使用错误的指针;他们很幸运,因为H264比特流的性质和他们使用缓冲区)
2)输入的已处理部分的长度。输入可能并且可能包含几个帧或帧的不完整部分。您应该使用其余输入再次调用该函数(并再次,再次,直到解析整个数据块)。如果你仔细检查你的例子,你会看到它做到了,你的代码没有。
此外,您可能不需要缓冲传入的数据,因为解析器应该在内部缓冲不完整的帧。