原H264采用libav codeC在MPEGTS容器框架 [英] Raw H264 frames in mpegts container using libavcodec
问题描述
我真的AP preciate一些帮助了以下问题:
I would really appreciate some help with the following issue:
我有一个小工具,带摄像头,产H264 COM pressed视频帧,这些帧被发送到我的应用程序。这些帧是不是在一个容器中,只是原始数据
I have a gadget with a camera, producing H264 compressed video frames, these frames are being sent to my application. These frames are not in a container, just raw data.
我想使用的ffmpeg和libav函数创建一个视频文件,以后可以使用。
I want to use ffmpeg and libav functions to create a video file, which can be used later.
如果我去code中的帧,然后连接code他们,一切工作正常,我得到一个有效的视频文件。 (去code / EN code步骤是通常libav命令,没有什么花哨这里,我把他们从全能互联网,他们是稳如泰山)...但是,我通过解码浪费了大量的时间和编码,所以我想跳过这一步,直接把帧输出流。现在,问题来了。
If I decode the frames, then encode them, everything works fine, I get a valid video file. (the decode/encode steps are the usual libav commands, nothing fancy here, I took them from the almighty internet, they are rock solid)... However, I waste a lot of time by decoding and encoding, so I would like to skip this step and directly put the frames in the output stream. Now, the problems come.
下面是我想出了用于产生编码code:
Here is the code I came up with for producing the encoding:
AVFrame* picture;
avpicture_fill((AVPicture*) picture, (uint8_t*)frameData,
codecContext->pix_fmt, codecContext->width,
codecContext->height);
int outSize = avcodec_encode_video(codecContext, videoOutBuf,
sizeof(videoOutBuf), picture);
if (outSize > 0)
{
AVPacket packet;
av_init_packet(&packet);
packet.pts = av_rescale_q(codecContext->coded_frame->pts,
codecContext->time_base, videoStream->time_base);
if (codecContext->coded_frame->key_frame)
{
packet.flags |= PKT_FLAG_KEY;
}
packet.stream_index = videoStream->index;
packet.data = videoOutBuf;
packet.size = outSize;
av_interleaved_write_frame(context, &packet);
put_flush_packet(context->pb);
}
当变量是这样的:
Where the variables are like:
frameData code>是德codeD帧数据,即从相机问世,它是在一个previous一步去codeD和
videoOutBuf
是一个纯uint8_t有缓冲用于保存数据
frameData
is the decoded frame data, that came from the camera, it was decoded in a previous step and videoOutBuf
is a plain uint8_t buffer for holding the data
我已经修改以便不脱code中的帧中的应用,而是简单地通过像数据
I have modified the application in order to not to decode the frames, but simply pass through the data like:
AVPacket packet;
av_init_packet(&packet);
packet.stream_index = videoStream->index;
packet.data = (uint8_t*)frameData;
packet.size = currentFrameSize;
av_interleaved_write_frame(context, &packet);
put_flush_packet(context->pb);
其中,
frameData code>是原始H264框架
和 currentFrameSize
是原始H264帧的大小,即得。字节数,我从这个小工具的每一帧得到的。
frameData
is the raw H264 frame
and currentFrameSize
is the size of the raw H264 frame, ie. the number of bytes I get from the gadget for every frame.
和突然的应用程序无法正常工作了,所产生的视频播放。这是显而易见的,因为我没有为数据包设置一个正确的PTS。我所做的是下面的(我绝望了,你可以从这个方法:)看到它)
And suddenly the application is not working correctly anymore, the produced video is unplayable. This is obvious, since I was not setting a correct PTS for the packet. What I did was the following (I'm desperate, you can see it from this approach :) )
packet.pts = timestamps[timestamp_counter ++];
其中,时间戳
实际上是由工作code以上生产PTS的列表,并写入到一个文件中(是的,你正确地读它,我记录的所有该PTS对10分钟的会议,并希望使用它们)。
where timestamps
is actually a list of PTS's produced by the working code above, and written to a file (yes, you read it properly, I logged all the PTS's for a 10 minute session, and wanted to use them).
应用程序仍然无法正常工作。
The application still does not work.
现在,我在这里没有任何线索做什么,所以这里的问题:
Now, here I am without any clue what to do, so here is the question:
我想创建一个使用libav功能的MPEGTS的视频流,数据流中插入已连接codeD的视频帧,并创建视频文件吧。我该怎么做呢?
I would like to create an "mpegts" video stream using libav functions, insert in the stream already encoded video frames and create a video file with it. How do I do it?
谢谢,
F。
推荐答案
我相信,如果你设置以下,你会看到视频播放。
I believe if you set the following, you will see video playback.
packet.flags |= AV_PKT_FLAG_KEY;
packet.pts = packet.dts = 0;
您应根据H264数据包报头真定packet.flags。您可以尝试这家伙叠overflowian 的建议,直接从流中提取。
You should really set packet.flags according to the h264 packet headers. You might try this fellow stack overflowian's suggestion for extracting directly from the stream.
如果您还添加声音,然后PTS / DTS将是更重要的。我建议你学习本教程
If you are also adding audio, then pts/dts is going to be more important. I suggest you study this tutorial
修改
我发现时间把解压出来是什么从我的测试应用程序为我工作。出于某种原因,DTS / PTS的零价值的作品对我来说,但比0值以外或AV_NOPTS_VALUE没有。不知大家有不同的版本的ffmpeg。我从 git的最新://git.videolan.org/ffmpeg.git
I found time to extract out what is working for me from my test app. For some reason, dts/pts values of zero works for me, but values other than 0 or AV_NOPTS_VALUE do not. I wonder if we have different versions of ffmpeg. I have the latest from git://git.videolan.org/ffmpeg.git.
fftest.cpp
#include <string>
#ifndef INT64_C
#define INT64_C(c) (c ## LL)
#define UINT64_C(c) (c ## ULL)
#endif
//#define _M
#define _M printf( "%s(%d) : MARKER\n", __FILE__, __LINE__ )
extern "C"
{
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
};
AVFormatContext *fc = 0;
int vi = -1, waitkey = 1;
// < 0 = error
// 0 = I-Frame
// 1 = P-Frame
// 2 = B-Frame
// 3 = S-Frame
int getVopType( const void *p, int len )
{
if ( !p || 6 >= len )
return -1;
unsigned char *b = (unsigned char*)p;
// Verify NAL marker
if ( b[ 0 ] || b[ 1 ] || 0x01 != b[ 2 ] )
{ b++;
if ( b[ 0 ] || b[ 1 ] || 0x01 != b[ 2 ] )
return -1;
} // end if
b += 3;
// Verify VOP id
if ( 0xb6 == *b )
{ b++;
return ( *b & 0xc0 ) >> 6;
} // end if
switch( *b )
{ case 0x65 : return 0;
case 0x61 : return 1;
case 0x01 : return 2;
} // end switch
return -1;
}
void write_frame( const void* p, int len )
{
if ( 0 > vi )
return;
AVStream *pst = fc->streams[ vi ];
// Init packet
AVPacket pkt;
av_init_packet( &pkt );
pkt.flags |= ( 0 >= getVopType( p, len ) ) ? AV_PKT_FLAG_KEY : 0;
pkt.stream_index = pst->index;
pkt.data = (uint8_t*)p;
pkt.size = len;
// Wait for key frame
if ( waitkey )
if ( 0 == ( pkt.flags & AV_PKT_FLAG_KEY ) )
return;
else
waitkey = 0;
pkt.dts = AV_NOPTS_VALUE;
pkt.pts = AV_NOPTS_VALUE;
// av_write_frame( fc, &pkt );
av_interleaved_write_frame( fc, &pkt );
}
void destroy()
{
waitkey = 1;
vi = -1;
if ( !fc )
return;
_M; av_write_trailer( fc );
if ( fc->oformat && !( fc->oformat->flags & AVFMT_NOFILE ) && fc->pb )
avio_close( fc->pb );
// Free the stream
_M; av_free( fc );
fc = 0;
_M;
}
int get_nal_type( void *p, int len )
{
if ( !p || 5 >= len )
return -1;
unsigned char *b = (unsigned char*)p;
// Verify NAL marker
if ( b[ 0 ] || b[ 1 ] || 0x01 != b[ 2 ] )
{ b++;
if ( b[ 0 ] || b[ 1 ] || 0x01 != b[ 2 ] )
return -1;
} // end if
b += 3;
return *b;
}
int create( void *p, int len )
{
if ( 0x67 != get_nal_type( p, len ) )
return -1;
destroy();
const char *file = "test.avi";
CodecID codec_id = CODEC_ID_H264;
// CodecID codec_id = CODEC_ID_MPEG4;
int br = 1000000;
int w = 480;
int h = 354;
int fps = 15;
// Create container
_M; AVOutputFormat *of = av_guess_format( 0, file, 0 );
fc = avformat_alloc_context();
fc->oformat = of;
strcpy( fc->filename, file );
// Add video stream
_M; AVStream *pst = av_new_stream( fc, 0 );
vi = pst->index;
AVCodecContext *pcc = pst->codec;
_M; avcodec_get_context_defaults2( pcc, AVMEDIA_TYPE_VIDEO );
pcc->codec_type = AVMEDIA_TYPE_VIDEO;
pcc->codec_id = codec_id;
pcc->bit_rate = br;
pcc->width = w;
pcc->height = h;
pcc->time_base.num = 1;
pcc->time_base.den = fps;
// Init container
_M; av_set_parameters( fc, 0 );
if ( !( fc->oformat->flags & AVFMT_NOFILE ) )
avio_open( &fc->pb, fc->filename, URL_WRONLY );
_M; av_write_header( fc );
_M; return 1;
}
int main( int argc, char** argv )
{
int f = 0, sz = 0;
char fname[ 256 ] = { 0 };
char buf[ 128 * 1024 ];
av_log_set_level( AV_LOG_ERROR );
av_register_all();
do
{
// Raw frames in v0.raw, v1.raw, v2.raw, ...
// sprintf( fname, "rawvideo/v%lu.raw", f++ );
sprintf( fname, "frames/frame%lu.bin", f++ );
printf( "%s\n", fname );
FILE *fd = fopen( fname, "rb" );
if ( !fd )
sz = 0;
else
{
sz = fread( buf, 1, sizeof( buf ) - FF_INPUT_BUFFER_PADDING_SIZE, fd );
if ( 0 < sz )
{
memset( &buf[ sz ], 0, FF_INPUT_BUFFER_PADDING_SIZE );
if ( !fc )
create( buf, sz );
if ( fc )
write_frame( buf, sz );
} // end if
fclose( fd );
} // end else
} while ( 0 < sz );
destroy();
}
这篇关于原H264采用libav codeC在MPEGTS容器框架的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!