Too large number of skipped frames. FFMPEG, C program - c

I'm writing program on C to capture RTSP stream and write it to files.
But after some time i get errors:
Too large number of skipped frames xxxx > 60000
After this files become incorrect and very small size.
What the reason of it and how can o fix this problems?
a piece of code, where i capture frames and put them to buffer.
ofmt = av_guess_format( NULL, sFileOutput, NULL );
ofcx = avformat_alloc_context();
ofcx->oformat = ofmt;
int ret2=avio_open( &ofcx->pb, sFileOutput, AVIO_FLAG_WRITE);
if(ret2<0){
fprintf(stderr, "\nError occurred when opening output file: %s\n",av_err2str(ret2));
}
ost = avformat_new_stream( ofcx, NULL );
avcodec_copy_context( ost->codec, iccx );
ost->sample_aspect_ratio.num = iccx->sample_aspect_ratio.num;
ost->sample_aspect_ratio.den = iccx->sample_aspect_ratio.den;
ost->r_frame_rate = ist->r_frame_rate;
ost->avg_frame_rate = ost->r_frame_rate;
ost->time_base = av_inv_q( ost->r_frame_rate );
ost->codec->time_base = ost->time_base;
ost->codec->width = 1280;
ost->codec->height = 800;
av_init_packet( &pkt );
while ( av_read_frame( ifcx, &pkt ) >= 0 && start_flag==0 && stop_flag==0){
if ( pkt.stream_index == i_index ) {
pkt.stream_index = ost->id;
pkt.pts = av_rescale_q_rnd(pkt.pts, ist->time_base, ost->time_base, AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX);
pkt.dts = av_rescale_q_rnd(pkt.dts, ist->time_base, ost->time_base, AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX);
pkt.duration = av_rescale_q(pkt.duration, ist->time_base, ost->time_base);
pkt.pos = -1;
av_copy_packet(&pkt_arr[pkg_index],&pkt);
}
av_free_packet( &pkt );
av_init_packet( &pkt );
pkg_index++;
if(pkg_index>=bufer_size){
pkg_index=pkg_index-bufer_size;
}
}

Related

DirectX: The best way to get RGB data from ID3D11Texture2D with DXGI_FORMAT_NV12 format?

I'm using DirectX to draw videos. After decoding by Intel Media SDK. And then I draw it by the following Intel's Code:
mfxStatus CD3D11Device::RenderFrame(mfxFrameSurface1 * pSrf, mfxFrameAllocator * pAlloc)
{
HRESULT hres = S_OK;
mfxStatus sts;
sts = CreateVideoProcessor(pSrf);
MSDK_CHECK_STATUS(sts, "CreateVideoProcessor failed");
hres = m_pSwapChain->GetBuffer(0, __uuidof( ID3D11Texture2D ), (void**)&m_pDXGIBackBuffer.p);
if (FAILED(hres))
return MFX_ERR_DEVICE_FAILED;
D3D11_VIDEO_PROCESSOR_OUTPUT_VIEW_DESC OutputViewDesc;
if (2 == m_nViews)
{
m_pVideoContext->VideoProcessorSetStreamStereoFormat(m_pVideoProcessor, 0, TRUE,D3D11_VIDEO_PROCESSOR_STEREO_FORMAT_SEPARATE,
TRUE, TRUE, D3D11_VIDEO_PROCESSOR_STEREO_FLIP_NONE, NULL);
m_pVideoContext->VideoProcessorSetOutputStereoMode(m_pVideoProcessor,TRUE);
OutputViewDesc.ViewDimension = D3D11_VPOV_DIMENSION_TEXTURE2DARRAY;
OutputViewDesc.Texture2DArray.ArraySize = 2;
OutputViewDesc.Texture2DArray.MipSlice = 0;
OutputViewDesc.Texture2DArray.FirstArraySlice = 0;
}
else
{
OutputViewDesc.ViewDimension = D3D11_VPOV_DIMENSION_TEXTURE2D;
OutputViewDesc.Texture2D.MipSlice = 0;
}
if (1 == m_nViews || 0 == pSrf->Info.FrameId.ViewId)
{
hres = m_pDX11VideoDevice->CreateVideoProcessorOutputView(
m_pDXGIBackBuffer,
m_VideoProcessorEnum,
&OutputViewDesc,
&m_pOutputView.p );
if (FAILED(hres))
return MFX_ERR_DEVICE_FAILED;
}
D3D11_VIDEO_PROCESSOR_INPUT_VIEW_DESC InputViewDesc;
InputViewDesc.FourCC = 0;
InputViewDesc.ViewDimension = D3D11_VPIV_DIMENSION_TEXTURE2D;
InputViewDesc.Texture2D.MipSlice = 0;
InputViewDesc.Texture2D.ArraySlice = 0;
mfxHDLPair pair = {NULL};
sts = pAlloc->GetHDL(pAlloc->pthis, pSrf->Data.MemId, (mfxHDL*)&pair);
MSDK_CHECK_STATUS(sts, "pAlloc->GetHDL failed");
ID3D11Texture2D *pRTTexture2D = reinterpret_cast<ID3D11Texture2D*>(pair.first);
D3D11_TEXTURE2D_DESC RTTexture2DDesc;
if(!m_pTempTexture && m_nViews == 2)
{
pRTTexture2D->GetDesc(&RTTexture2DDesc);
hres = m_pD3D11Device->CreateTexture2D(&RTTexture2DDesc,NULL,&m_pTempTexture.p);
if (FAILED(hres))
return MFX_ERR_DEVICE_FAILED;
}
// Creating input views for left and righ eyes
if (1 == m_nViews)
{
hres = m_pDX11VideoDevice->CreateVideoProcessorInputView(
pRTTexture2D,
m_VideoProcessorEnum,
&InputViewDesc,
&m_pInputViewLeft.p );
}
else if (2 == m_nViews && 0 == pSrf->Info.FrameId.ViewId)
{
m_pD3D11Ctx->CopyResource(m_pTempTexture,pRTTexture2D);
hres = m_pDX11VideoDevice->CreateVideoProcessorInputView(
m_pTempTexture,
m_VideoProcessorEnum,
&InputViewDesc,
&m_pInputViewLeft.p );
}
else
{
hres = m_pDX11VideoDevice->CreateVideoProcessorInputView(
pRTTexture2D,
m_VideoProcessorEnum,
&InputViewDesc,
&m_pInputViewRight.p );
}
if (FAILED(hres))
return MFX_ERR_DEVICE_FAILED;
// NV12 surface to RGB backbuffer
RECT rect = {0};
rect.right = pSrf->Info.CropW;
rect.bottom = pSrf->Info.CropH;
D3D11_VIDEO_PROCESSOR_STREAM StreamData;
if (1 == m_nViews || pSrf->Info.FrameId.ViewId == 1)
{
StreamData.Enable = TRUE;
StreamData.OutputIndex = 0;
StreamData.InputFrameOrField = 0;
StreamData.PastFrames = 0;
StreamData.FutureFrames = 0;
StreamData.ppPastSurfaces = NULL;
StreamData.ppFutureSurfaces = NULL;
StreamData.pInputSurface = m_pInputViewLeft;
StreamData.ppPastSurfacesRight = NULL;
StreamData.ppFutureSurfacesRight = NULL;
StreamData.pInputSurfaceRight = m_nViews == 2 ? m_pInputViewRight : NULL;
m_pVideoContext->VideoProcessorSetStreamSourceRect(m_pVideoProcessor, 0, true, &rect);
m_pVideoContext->VideoProcessorSetStreamFrameFormat( m_pVideoProcessor, 0, D3D11_VIDEO_FRAME_FORMAT_PROGRESSIVE);
hres = m_pVideoContext->VideoProcessorBlt( m_pVideoProcessor, m_pOutputView, 0, 1, &StreamData );
if (FAILED(hres))
return MFX_ERR_DEVICE_FAILED;
}
if (1 == m_nViews || 1 == pSrf->Info.FrameId.ViewId)
{
DXGI_PRESENT_PARAMETERS parameters = {0};
hres = m_pSwapChain->Present1(0, 0, &parameters);
if (FAILED(hres))
return MFX_ERR_DEVICE_FAILED;
}
return MFX_ERR_NONE;
}
From the code's line:
ID3D11Texture2D *pRTTexture2D = reinterpret_cast<ID3D11Texture2D*>(pair.first);
I had pRTTexture2D is a ID3D11Texture2D with DXGI_FORMAT_NV12 format.
I want to get RGB data from this texture, and I tried to using the below way:
1) Map the texture use d3dContext->Map(Texture, 0, D3D11_MAP_READ, 0, &mapInfo) => must copy to the staging resource in my case
2) Create a RGB Array on System Memory and calculate to convert from NV12 on mapInfo to RGB Array.
This way worked ok, but I want to do it with the better way. Because I guess that while rendering (RenderFrame() Function) the DirectX converted Texture in to RGB in BackBuffer, and if I can get data form that BackBuffer, that will be great.
Someone can show me the code to do above way. Or is there any better way to implement it?
Thank you very much!
D3DXSaveSurfaceToFileInMemory, use this API, Maybe it can bring you some ideas.

Not able to decode mp4 file using latest ffmpeg library : av_decode_video2

I am writing a wrapper code around latest ffmpeg library. I am supplying MP4 files from local system. My problem is that I am unable to get any decoded frames when I use av_decode_video2(). The return value comes out to be negative. I have used av_read_frame() which returns 0. I googled about the problem I am facing but no where could I find the correct explanation. Please give me insight here. Pasting the pseudo code here.
av_init_packet(avpkt);
picture=av_frame_alloc();
pFrameRGB=av_frame_alloc();
codec = avcodec_find_decoder(CODEC_ID_H264);
c= avcodec_alloc_context3(codec)
avcodec_open2(decoderLibraryData->c, decoderLibraryData->codec, NULL)
FormatContext = avformat_alloc_context();
char *pUrl ="./1.MP4";
iRet = avformat_open_input(atContext, pUrl, pFmt, NULL);
if(FormatContext == NULL)
{
printf("could not assign any memory !!!!!!!!! \n");
}
avformat_find_stream_info(FormatContext, NULL);
while(av_read_frame(FormatContext,avpkt) >= 0)
{
len = avcodec_decode_video2(c, picture, &got_picture,avpkt);
printf("CODEC MANAGER len %d Frame decompressed %d \n",len,got_picture);
if (len <= 0)
{
return ERROR;
}
}
}
if(lastHeight != 0 && lastWidth != 0)
{
if(lastWidth != c->width || lastHeight != c->height )
{
av_free(buffer);
buffer = NULL;
lastWidth = c->width;
lastHeight = c->height;
}
}
else
{
lastWidth = c->width;
lastHeight = c->height;
}
decodeFlag = 1;
if(!buffer)
{
int numBytes;
v_mutex_lock(globalCodecLock);
switch(inPixFormat)
{
case RGB:
// Determine required buffer size and allocate buffer
numBytes=avpicture_get_size(PIX_FMT_RGB24, c->width, c->height);
buffer=(uint8_t *)av_malloc(numBytes*sizeof(uint8_t));
avpicture_fill((AVPicture *)pFrameRGB,buffer,PIX_FMT_RGB24,c->width, c->height);
if(cntxt)
sws_freeContext(cntxt);
cntxt = sws_getContext(c->width, c->height, c->pix_fmt,
c->width, c->height, PIX_FMT_RGB24, SWS_BICUBIC, NULL, NULL, NULL);
break;
}
v_mutex_unlock(globalCodecLock);
if(cntxt == NULL)
{
printf("sws_getContext error\n");
return ERROR;
}
}
{
sws_scale(cntxt, picture->data, picture->linesize, 0, c->height, pFrameRGB->data, pFrameRGB->linesize);
if(rgbBuff)
{
if(c->width <= *width && c->height <= *height)
{
saveFrame(pFrameRGB, c->width, c->height, rgbBuff,inPixFormat);
*width = c->width;
*height = c->height;
rs = SUCCESS;
break;
}
else
{
rs = VA_LOWBUFFERSIZE;
}
}
else
{
rs = VA_LOWBUFFERSIZE;
}
}
if(width)
{
*width = c->width;
}
if(height)
{
*height = c->height;
}
if(rs == VA_LOWBUFFERSIZE)
{
break;
}
I am getting the return value of av_read_frame as 0 but av_decode_video2 returns value in negative. I am not able to get any clue here.
Make sure you have called
av_register_all();
or
avcodec_register_all();
at the beginning of your app.
Also it seems the problem is from calling avformat_find_stream_info. Test with the following code:
AVPacket avpkt;
av_init_packet(&avpkt);
AVFrame* picture = av_frame_alloc();
AVFrame* pFrameRGB = av_frame_alloc();
AVFormatContext* c2 = avformat_alloc_context();
char *pUrl = "C:/Sample Videos/20-06-34.MP4";
int video_stream_index = 0;
AVInputFormat* pFmt;
int iRet = avformat_open_input(&c2, pUrl, pFmt, NULL);
AVStream* stream = c2->streams[video_stream_index];
AVCodec* codec = avcodec_find_decoder(stream->codec->codec_id);
avcodec_open2(stream->codec, codec, NULL);
if (c2 == NULL)
{
printf("could not assign any memory !!!!!!!!! \n");
}
while (av_read_frame(c2, &avpkt) >= 0)
{
int got_picture;
int len = avcodec_decode_video2(stream->codec, picture, &got_picture, &avpkt);
printf("CODEC MANAGER len %d Frame decompressed %d \n", len, got_picture);
if (len <= 0)
{
return ERROR;
}
}

How to cut video with FFmpeg C API

How can I cut video with FFmpeg C API? From 00:10:00 to 00:20:00 for example.
What functions I need to use?
I convert video using this function:
int convert(char *file) {
AVFrame *frame;
AVPacket inPacket, outPacket;
if(avio_open(&outFormatContext->pb, file, AVIO_FLAG_WRITE) < 0) {
fprintf(stderr, "convert(): cannot open out file\n");
return 0;
}
avformat_write_header(outFormatContext, NULL);
frame = avcodec_alloc_frame();
av_init_packet(&inPacket);
while(av_read_frame(inFormatContext, &inPacket) >= 0) {
if(inPacket.stream_index == inVideoStreamIndex) {
avcodec_decode_video2(inCodecContext, frame, &frameFinished, &inPacket);
if(frameFinished) {
av_init_packet(&outPacket);
avcodec_encode_video2(outCodecContext, &outPacket, frame, &outputed);
if(outputed) {
if (av_write_frame(outFormatContext, &outPacket) != 0) {
fprintf(stderr, "convert(): error while writing video frame\n");
return 0;
}
}
av_free_packet(&outPacket);
}
}
}
av_write_trailer(outFormatContext);
av_free_packet(&inPacket);
return 1;
}
As Wagner Patriota says, "if you just wanna cut the video, you don't need to reencode the video if you want". Here is the code based on ffmpeg remuxing.c example that you don't need to reencode the video.
#include <libavutil/timestamp.h>
#include <libavformat/avformat.h>
static void log_packet(const AVFormatContext *fmt_ctx, const AVPacket *pkt, const char *tag)
{
AVRational *time_base = &fmt_ctx->streams[pkt->stream_index]->time_base;
printf("%s: pts:%s pts_time:%s dts:%s dts_time:%s duration:%s duration_time:%s stream_index:%d\n",
tag,
av_ts2str(pkt->pts), av_ts2timestr(pkt->pts, time_base),
av_ts2str(pkt->dts), av_ts2timestr(pkt->dts, time_base),
av_ts2str(pkt->duration), av_ts2timestr(pkt->duration, time_base),
pkt->stream_index);
}
int cut_video(double from_seconds, double end_seconds, const char* in_filename, const char* out_filename) {
AVOutputFormat *ofmt = NULL;
AVFormatContext *ifmt_ctx = NULL, *ofmt_ctx = NULL;
AVPacket pkt;
int ret, i;
av_register_all();
if ((ret = avformat_open_input(&ifmt_ctx, in_filename, 0, 0)) < 0) {
fprintf(stderr, "Could not open input file '%s'", in_filename);
goto end;
}
if ((ret = avformat_find_stream_info(ifmt_ctx, 0)) < 0) {
fprintf(stderr, "Failed to retrieve input stream information");
goto end;
}
av_dump_format(ifmt_ctx, 0, in_filename, 0);
avformat_alloc_output_context2(&ofmt_ctx, NULL, NULL, out_filename);
if (!ofmt_ctx) {
fprintf(stderr, "Could not create output context\n");
ret = AVERROR_UNKNOWN;
goto end;
}
ofmt = ofmt_ctx->oformat;
for (i = 0; i < ifmt_ctx->nb_streams; i++) {
AVStream *in_stream = ifmt_ctx->streams[i];
AVStream *out_stream = avformat_new_stream(ofmt_ctx, in_stream->codec->codec);
if (!out_stream) {
fprintf(stderr, "Failed allocating output stream\n");
ret = AVERROR_UNKNOWN;
goto end;
}
ret = avcodec_copy_context(out_stream->codec, in_stream->codec);
if (ret < 0) {
fprintf(stderr, "Failed to copy context from input to output stream codec context\n");
goto end;
}
out_stream->codec->codec_tag = 0;
if (ofmt_ctx->oformat->flags & AVFMT_GLOBALHEADER)
out_stream->codec->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
}
av_dump_format(ofmt_ctx, 0, out_filename, 1);
if (!(ofmt->flags & AVFMT_NOFILE)) {
ret = avio_open(&ofmt_ctx->pb, out_filename, AVIO_FLAG_WRITE);
if (ret < 0) {
fprintf(stderr, "Could not open output file '%s'", out_filename);
goto end;
}
}
ret = avformat_write_header(ofmt_ctx, NULL);
if (ret < 0) {
fprintf(stderr, "Error occurred when opening output file\n");
goto end;
}
// int indexs[8] = {0};
// int64_t start_from = 8*AV_TIME_BASE;
ret = av_seek_frame(ifmt_ctx, -1, from_seconds*AV_TIME_BASE, AVSEEK_FLAG_ANY);
if (ret < 0) {
fprintf(stderr, "Error seek\n");
goto end;
}
int64_t *dts_start_from = malloc(sizeof(int64_t) * ifmt_ctx->nb_streams);
memset(dts_start_from, 0, sizeof(int64_t) * ifmt_ctx->nb_streams);
int64_t *pts_start_from = malloc(sizeof(int64_t) * ifmt_ctx->nb_streams);
memset(pts_start_from, 0, sizeof(int64_t) * ifmt_ctx->nb_streams);
while (1) {
AVStream *in_stream, *out_stream;
ret = av_read_frame(ifmt_ctx, &pkt);
if (ret < 0)
break;
in_stream = ifmt_ctx->streams[pkt.stream_index];
out_stream = ofmt_ctx->streams[pkt.stream_index];
log_packet(ifmt_ctx, &pkt, "in");
if (av_q2d(in_stream->time_base) * pkt.pts > end_seconds) {
av_free_packet(&pkt);
break;
}
if (dts_start_from[pkt.stream_index] == 0) {
dts_start_from[pkt.stream_index] = pkt.dts;
printf("dts_start_from: %s\n", av_ts2str(dts_start_from[pkt.stream_index]));
}
if (pts_start_from[pkt.stream_index] == 0) {
pts_start_from[pkt.stream_index] = pkt.pts;
printf("pts_start_from: %s\n", av_ts2str(pts_start_from[pkt.stream_index]));
}
/* copy packet */
pkt.pts = av_rescale_q_rnd(pkt.pts - pts_start_from[pkt.stream_index], in_stream->time_base, out_stream->time_base, AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX);
pkt.dts = av_rescale_q_rnd(pkt.dts - dts_start_from[pkt.stream_index], in_stream->time_base, out_stream->time_base, AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX);
if (pkt.pts < 0) {
pkt.pts = 0;
}
if (pkt.dts < 0) {
pkt.dts = 0;
}
pkt.duration = (int)av_rescale_q((int64_t)pkt.duration, in_stream->time_base, out_stream->time_base);
pkt.pos = -1;
log_packet(ofmt_ctx, &pkt, "out");
printf("\n");
ret = av_interleaved_write_frame(ofmt_ctx, &pkt);
if (ret < 0) {
fprintf(stderr, "Error muxing packet\n");
break;
}
av_free_packet(&pkt);
}
free(dts_start_from);
free(pts_start_from);
av_write_trailer(ofmt_ctx);
end:
avformat_close_input(&ifmt_ctx);
/* close output */
if (ofmt_ctx && !(ofmt->flags & AVFMT_NOFILE))
avio_closep(&ofmt_ctx->pb);
avformat_free_context(ofmt_ctx);
if (ret < 0 && ret != AVERROR_EOF) {
fprintf(stderr, "Error occurred: %s\n", av_err2str(ret));
return 1;
}
return 0;
}
If you just wanna cut the video, you don't need to reencode the video if you want.
So I am supposing you wanna cut and reencode for some reason. So, based on your code:
Observe you must to have access to the video AVStream* structure... I named it as inVideoStream.
int convert_and_cut(char *file, float starttime, float endtime) {
AVFrame *frame;
AVPacket inPacket, outPacket;
if(avio_open(&outFormatContext->pb, file, AVIO_FLAG_WRITE) < 0) {
fprintf(stderr, "convert(): cannot open out file\n");
return 0;
}
// seek to the start time you wish.
// BEGIN
AVRational default_timebase;
default_timebase.num = 1;
default_timebase.den = AV_TIME_BASE;
// suppose you have access to the "inVideoStream" of course
int64_t starttime_int64 = av_rescale_q((int64_t)( starttime * AV_TIME_BASE ), default_timebase, inVideoStream->time_base);
int64_t endtime_int64 = av_rescale_q((int64_t)( endtime * AV_TIME_BASE ), default_timebase, inVideoStream->time_base);
if(avformat_seek_file(inFormatContext, inVideoStreamIndex, INT64_MIN, starttime_int64, INT64_MAX, 0) < 0) {
// error... do something...
return 0; // usually 0 is used for success in C, but I am following your code.
}
avcodec_flush_buffers( inVideoStream->codec );
// END
avformat_write_header(outFormatContext, NULL);
frame = avcodec_alloc_frame();
av_init_packet(&inPacket);
// you used avformat_seek_file() to seek CLOSE to the point you want... in order to give precision to your seek,
// just go on reading the packets and checking the packets PTS (presentation timestamp)
while(av_read_frame(inFormatContext, &inPacket) >= 0) {
if(inPacket.stream_index == inVideoStreamIndex) {
avcodec_decode_video2(inCodecContext, frame, &frameFinished, &inPacket);
// this line guarantees you are getting what you really want.
if(frameFinished && frame->pkt_pts >= starttime_int64 && frame->pkt_pts <= endtime_int64) {
av_init_packet(&outPacket);
avcodec_encode_video2(outCodecContext, &outPacket, frame, &outputed);
if(outputed) {
if (av_write_frame(outFormatContext, &outPacket) != 0) {
fprintf(stderr, "convert(): error while writing video frame\n");
return 0;
}
}
av_free_packet(&outPacket);
}
// exit the loop if you got the frames you want.
if(frame->pkt_pts > endtime_int64) {
break;
}
}
}
av_write_trailer(outFormatContext);
av_free_packet(&inPacket);
return 1;
}
In addition, as ustin says, the code based on ffmpeg remuxing.c example.
add out_stream->time_base = in_stream->time_base; before out_stream->codec->codec_tag = 0;
add int64_t *start_from = NULL; after int stream_mapping_size = 0;
add start_from = av_mallocz_array(stream_mapping_size, sizeof(*start_from)); after stream_mapping = av_mallocz_array(stream_mapping_size, sizeof(*stream_mapping));
add start_from[stream_mapping[i]] = INT16_MIN; after stream_mapping[i] = stream_index++;
add
if (start_from[pkt.stream_index] == INT16_MIN) {
int64_t dts = pkt.dts;
int64_t pts = pkt.pts;
int64_t min_ts = dts > pts ? pts : dts;
start_from[pkt.stream_index] = min_ts < 0 ? 0 : min_ts;
}
After
if (pkt.stream_index >= stream_mapping_size ||
stream_mapping[pkt.stream_index] < 0) {
av_packet_unref(&pkt);
continue;
}
change justin code, about pts/dst set value to this:
pkt.pts = av_rescale_q_rnd(pkt.pts - start_from[pkt.stream_index], in_stream->time_base, out_stream->time_base, AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX);
pkt.dts = av_rescale_q_rnd(pkt.dts - start_from[pkt.stream_index], in_stream->time_base, out_stream->time_base, AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX);
add free(start_from); before end:
Tips: start/end timestamp like justin says

how to stream h.264 video with mp3 audio using libavcodec?

I read h.264 frames from webcamera and capture audio from microphone. I need to stream live video to ffserver. During debug I read video from ffserver using ffmpeg with following command:
ffmpeg -i http://127.0.0.1:12345/robot.avi -vcodec copy -acodec copy out.avi
My video in output file is slightly accelerated. If I add a audio stream it is accelerated several times. Sometimes there is no audio in the output file.
Here is my code for encoding audio:
#include "v_audio_encoder.h"
extern "C" {
#include <libavcodec/avcodec.h>
}
#include <cassert>
struct VAudioEncoder::Private
{
AVCodec *m_codec;
AVCodecContext *m_context;
std::vector<uint8_t> m_outBuffer;
};
VAudioEncoder::VAudioEncoder( int sampleRate, int bitRate )
{
d = new Private( );
d->m_codec = avcodec_find_encoder( CODEC_ID_MP3 );
assert( d->m_codec );
d->m_context = avcodec_alloc_context3( d->m_codec );
// put sample parameters
d->m_context->channels = 2;
d->m_context->bit_rate = bitRate;
d->m_context->sample_rate = sampleRate;
d->m_context->sample_fmt = AV_SAMPLE_FMT_S16;
strcpy( d->m_context->codec_name, "libmp3lame" );
// open it
int res = avcodec_open2( d->m_context, d->m_codec, 0 );
assert( res >= 0 );
d->m_outBuffer.resize( d->m_context->frame_size );
}
VAudioEncoder::~VAudioEncoder( )
{
avcodec_close( d->m_context );
av_free( d->m_context );
delete d;
}
void VAudioEncoder::encode( const std::vector<uint32_t>& samples, std::vector<uint8_t>& outbuf )
{
assert( (int)samples.size( ) == d->m_context->frame_size );
int outSize = avcodec_encode_audio( d->m_context, d->m_outBuffer.data( ),
d->m_outBuffer.size( ), reinterpret_cast<const short*>( samples.data( ) ) );
if( outSize ) {
outbuf.resize( outSize );
memcpy( outbuf.data( ), d->m_outBuffer.data( ), outSize );
}
else
outbuf.clear( );
}
int VAudioEncoder::getFrameSize( ) const
{
return d->m_context->frame_size;
}
Here is my code for streaming video:
#include "v_out_video_stream.h"
extern "C" {
#include <libavformat/avformat.h>
#include <libavutil/opt.h>
#include <libavutil/avstring.h>
#include <libavformat/avio.h>
}
#include <stdexcept>
#include <cassert>
struct VStatticRegistrar
{
VStatticRegistrar( )
{
av_register_all( );
avformat_network_init( );
}
};
VStatticRegistrar __registrar;
struct VOutVideoStream::Private
{
AVFormatContext * m_context;
int m_videoStreamIndex;
int m_audioStreamIndex;
int m_videoBitrate;
int m_width;
int m_height;
int m_fps;
int m_bitrate;
bool m_waitKeyFrame;
};
VOutVideoStream::VOutVideoStream( int width, int height, int fps, int bitrate )
{
d = new Private( );
d->m_width = width;
d->m_height = height;
d->m_fps = fps;
d->m_context = 0;
d->m_videoStreamIndex = -1;
d->m_audioStreamIndex = -1;
d->m_bitrate = bitrate;
d->m_waitKeyFrame = true;
}
bool VOutVideoStream::connectToServer( const std::string& uri )
{
assert( ! d->m_context );
// initalize the AV context
d->m_context = avformat_alloc_context();
if( !d->m_context )
return false;
// get the output format
d->m_context->oformat = av_guess_format( "ffm", NULL, NULL );
if( ! d->m_context->oformat )
return false;
strcpy( d->m_context->filename, uri.c_str( ) );
// add an H.264 stream
AVStream *stream = avformat_new_stream( d->m_context, NULL );
if ( ! stream )
return false;
// initalize codec
AVCodecContext* codec = stream->codec;
if( d->m_context->oformat->flags & AVFMT_GLOBALHEADER )
codec->flags |= CODEC_FLAG_GLOBAL_HEADER;
codec->codec_id = CODEC_ID_H264;
codec->codec_type = AVMEDIA_TYPE_VIDEO;
strcpy( codec->codec_name, "libx264" );
// codec->codec_tag = ( unsigned('4') << 24 ) + (unsigned('6') << 16 ) + ( unsigned('2') << 8 ) + 'H';
codec->width = d->m_width;
codec->height = d->m_height;
codec->time_base.den = d->m_fps;
codec->time_base.num = 1;
codec->bit_rate = d->m_bitrate;
d->m_videoStreamIndex = stream->index;
// add an MP3 stream
stream = avformat_new_stream( d->m_context, NULL );
if ( ! stream )
return false;
// initalize codec
codec = stream->codec;
if( d->m_context->oformat->flags & AVFMT_GLOBALHEADER )
codec->flags |= CODEC_FLAG_GLOBAL_HEADER;
codec->codec_id = CODEC_ID_MP3;
codec->codec_type = AVMEDIA_TYPE_AUDIO;
strcpy( codec->codec_name, "libmp3lame" );
codec->sample_fmt = AV_SAMPLE_FMT_S16;
codec->channels = 2;
codec->bit_rate = 64000;
codec->sample_rate = 44100;
d->m_audioStreamIndex = stream->index;
// try to open the stream
if( avio_open( &d->m_context->pb, d->m_context->filename, AVIO_FLAG_WRITE ) < 0 )
return false;
// write the header
return avformat_write_header( d->m_context, NULL ) == 0;
}
void VOutVideoStream::disconnect( )
{
assert( d->m_context );
avio_close( d->m_context->pb );
avformat_free_context( d->m_context );
d->m_context = 0;
}
VOutVideoStream::~VOutVideoStream( )
{
if( d->m_context )
disconnect( );
delete d;
}
int VOutVideoStream::getVopType( const std::vector<uint8_t>& image )
{
if( image.size( ) < 6 )
return -1;
unsigned char *b = (unsigned char*)image.data( );
// Verify NAL marker
if( b[ 0 ] || b[ 1 ] || 0x01 != b[ 2 ] ) {
++b;
if ( b[ 0 ] || b[ 1 ] || 0x01 != b[ 2 ] )
return -1;
}
b += 3;
// Verify VOP id
if( 0xb6 == *b ) {
++b;
return ( *b & 0xc0 ) >> 6;
}
switch( *b ) {
case 0x65: return 0;
case 0x61: return 1;
case 0x01: return 2;
}
return -1;
}
bool VOutVideoStream::sendVideoFrame( std::vector<uint8_t>& image )
{
// Init packet
AVPacket pkt;
av_init_packet( &pkt );
pkt.flags |= ( 0 >= getVopType( image ) ) ? AV_PKT_FLAG_KEY : 0;
// Wait for key frame
if ( d->m_waitKeyFrame ) {
if( pkt.flags & AV_PKT_FLAG_KEY )
d->m_waitKeyFrame = false;
else
return true;
}
pkt.stream_index = d->m_videoStreamIndex;
pkt.data = image.data( );
pkt.size = image.size( );
pkt.pts = pkt.dts = AV_NOPTS_VALUE;
return av_write_frame( d->m_context, &pkt ) >= 0;
}
bool VOutVideoStream::sendAudioFrame( std::vector<uint8_t>& audio )
{
// Init packet
AVPacket pkt;
av_init_packet( &pkt );
pkt.stream_index = d->m_audioStreamIndex;
pkt.data = audio.data( );
pkt.size = audio.size( );
pkt.pts = pkt.dts = AV_NOPTS_VALUE;
return av_write_frame( d->m_context, &pkt ) >= 0;
}
Here is how I use it:
BOOST_AUTO_TEST_CASE(testSendingVideo)
{
const int framesToGrab = 90000;
VOutVideoStream stream( VIDEO_WIDTH, VIDEO_HEIGHT, FPS, VIDEO_BITRATE );
if( stream.connectToServer( URI ) ) {
VAudioEncoder audioEncoder( AUDIO_SAMPLE_RATE, AUDIO_BIT_RATE );
VAudioCapture microphone( MICROPHONE_NAME, AUDIO_SAMPLE_RATE, audioEncoder.getFrameSize( ) );
VLogitecCamera camera( VIDEO_WIDTH, VIDEO_HEIGHT );
BOOST_REQUIRE( camera.open( CAMERA_PORT ) );
BOOST_REQUIRE( camera.startCapturing( ) );
std::vector<uint8_t> image, encodedAudio;
std::vector<uint32_t> voice;
boost::system_time startTime;
int delta;
for( int i = 0; i < framesToGrab; ++i ) {
startTime = boost::posix_time::microsec_clock::universal_time( );
BOOST_REQUIRE( camera.read( image ) );
BOOST_REQUIRE( microphone.read( voice ) );
audioEncoder.encode( voice, encodedAudio );
BOOST_REQUIRE( stream.sendVideoFrame( image ) );
BOOST_REQUIRE( stream.sendAudioFrame( encodedAudio ) );
delta = ( boost::posix_time::microsec_clock::universal_time( ) - startTime ).total_milliseconds( );
if( delta < 1000 / FPS )
boost::thread::sleep( startTime + boost::posix_time::milliseconds( 1000 / FPS - delta ) );
}
BOOST_REQUIRE( camera.stopCapturing( ) );
BOOST_REQUIRE( camera.close( ) );
}
else
std::cout << "failed to connect to server" << std::endl;
}
I think my problem is in PTS and DTS. Can anyone help me?

C - Verify code signatures - Windows API

I need to verify code signatures of binaries. Microsoft Authenticode I think is the term. Is there a sane way to do this using the Windows API?
Have you looked at WinVerifyTrust ? Since it's not immediately obvious how to use it to verify the signature of a binary, you probably want to look at the sample code specifically for that.
How to find authenticode for drivers:
Disclaimer: I did not write this code.
BOOL VerifyEmbeddedSignature(LPCWSTR pwszSourceFile)
{
LONG lStatus;
GUID WintrustVerifyGuid = WINTRUST_ACTION_GENERIC_VERIFY_V2;
GUID DriverActionGuid = DRIVER_ACTION_VERIFY;
HANDLE hFile;
DWORD dwHash;
BYTE bHash[100];
HCATINFO hCatInfo;
HCATADMIN hCatAdmin;
WINTRUST_DATA wd = { 0 };
WINTRUST_FILE_INFO wfi = { 0 };
WINTRUST_CATALOG_INFO wci = { 0 };
////set up structs to verify files with cert signatures
memset(&wfi, 0, sizeof(wfi));
wfi.cbStruct = sizeof( WINTRUST_FILE_INFO );
wfi.pcwszFilePath = pwszSourceFile;
wfi.hFile = NULL;
wfi.pgKnownSubject = NULL;
memset(&wd, 0, sizeof(wd));
wd.cbStruct = sizeof( WINTRUST_DATA );
wd.dwUnionChoice = WTD_CHOICE_FILE;
wd.pFile = &wfi;
wd.dwUIChoice = WTD_UI_NONE;
wd.fdwRevocationChecks = WTD_REVOKE_NONE;
wd.dwStateAction = 0;
wd.dwProvFlags = WTD_SAFER_FLAG;
wd.hWVTStateData = NULL;
wd.pwszURLReference = NULL;
wd.pPolicyCallbackData = NULL;
wd.pSIPClientData = NULL;
wd.dwUIContext = 0;
lStatus = WinVerifyTrust( NULL, &WintrustVerifyGuid, &wd );
////if failed, try to verify using catalog files
if (lStatus != ERROR_SUCCESS)
{
//open the file
hFile = CreateFileW(pwszSourceFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE)
return FALSE;
dwHash = sizeof(bHash);
if (!CryptCATAdminCalcHashFromFileHandle(hFile, &dwHash, bHash, 0))
{
CloseHandle(hFile);
return FALSE;
}
//Create a string form of the hash (used later in pszMemberTag)
LPWSTR pszMemberTag = new WCHAR[dwHash * 2 + 1];
for ( DWORD dw = 0; dw < dwHash; ++dw )
{
wsprintfW( &pszMemberTag[dw * 2], L"%02X", bHash[dw] );
}
if (!CryptCATAdminAcquireContext(&hCatAdmin, &DriverActionGuid, 0))
{
CloseHandle(hFile);
return FALSE;
}
//find the catalog which contains the hash
hCatInfo = CryptCATAdminEnumCatalogFromHash(hCatAdmin, bHash, dwHash, 0, NULL);
if ( hCatInfo )
{
CATALOG_INFO ci = { 0 };
CryptCATCatalogInfoFromContext( hCatInfo, &ci, 0 );
memset(&wci, 0, sizeof(wci));
wci.cbStruct = sizeof( WINTRUST_CATALOG_INFO );
wci.pcwszCatalogFilePath = ci.wszCatalogFile;
wci.pcwszMemberFilePath = pwszSourceFile;
wci.pcwszMemberTag = pszMemberTag;
memset(&wd, 0, sizeof(wd));
wd.cbStruct = sizeof( WINTRUST_DATA );
wd.dwUnionChoice = WTD_CHOICE_CATALOG;
wd.pCatalog = &wci;
wd.dwUIChoice = WTD_UI_NONE;
wd.fdwRevocationChecks = WTD_STATEACTION_VERIFY;
wd.dwProvFlags = 0;
wd.hWVTStateData = NULL;
wd.pwszURLReference = NULL;
wd.pPolicyCallbackData = NULL;
wd.pSIPClientData = NULL;
wd.dwUIContext = 0;
lStatus = WinVerifyTrust( NULL, &WintrustVerifyGuid, &wd );
CryptCATAdminReleaseCatalogContext( hCatAdmin, hCatInfo, 0 );
}
CryptCATAdminReleaseContext( hCatAdmin, 0 );
delete[] pszMemberTag;
CloseHandle(hFile);
}
if (lStatus != ERROR_SUCCESS)
return false;
else
return true;
}
Here is the working code to verify a file (technically any file type).
#include <stdio.h>
#include <windows.h>
#include <Softpub.h>
#include <wincrypt.h>
#include <wintrust.h>
#include <mscat.h>
#include <atlbase.h>
// Link with the Wintrust.lib file.
#pragma comment (lib, "wintrust")
BOOL VerifySignature(LPCSTR path) //We will receive the char* filepath not wchar*
{
USES_CONVERSION;
LPCWSTR pwszSourceFile = A2W(path); //We convert the char* to wchar*
LONG lStatus;
GUID WintrustVerifyGuid = WINTRUST_ACTION_GENERIC_VERIFY_V2;
GUID DriverActionGuid = DRIVER_ACTION_VERIFY;
HANDLE hFile;
DWORD dwHash;
BYTE bHash[100];
HCATINFO hCatInfo;
HCATADMIN hCatAdmin;
WINTRUST_DATA wd = { 0 };
WINTRUST_FILE_INFO wfi = { 0 };
WINTRUST_CATALOG_INFO wci = { 0 };
////set up structs to verify files with cert signatures
wfi.cbStruct = sizeof(WINTRUST_FILE_INFO);
wfi.pcwszFilePath = pwszSourceFile;
wfi.hFile = NULL;
wfi.pgKnownSubject = NULL;
wd.cbStruct = sizeof(WINTRUST_DATA);
wd.pPolicyCallbackData = NULL;
wd.pSIPClientData = NULL;
wd.dwUIChoice = WTD_UI_NONE;
wd.fdwRevocationChecks = WTD_REVOKE_NONE;
wd.dwUnionChoice = WTD_CHOICE_FILE;
wd.pFile = &wfi;
wd.dwStateAction = WTD_STATEACTION_VERIFY;
wd.hWVTStateData = NULL;
wd.pwszURLReference = NULL;
wd.dwProvFlags |= WTD_CACHE_ONLY_URL_RETRIEVAL;
wd.dwUIContext = 0;
wd.pSignatureSettings = 0;
lStatus = WinVerifyTrust((HWND)INVALID_HANDLE_VALUE, &WintrustVerifyGuid, &wd);
wd.dwStateAction = WTD_STATEACTION_CLOSE;
WinVerifyTrust((HWND)INVALID_HANDLE_VALUE, &WintrustVerifyGuid, &wd); //close hWVTStateData
////if failed, try to verify using catalog files
if (lStatus != ERROR_SUCCESS)
{
//open the file
hFile = CreateFileW(pwszSourceFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE)
return FALSE;
dwHash = sizeof(bHash);
if (!CryptCATAdminCalcHashFromFileHandle(hFile, &dwHash, bHash, 0))
{
CloseHandle(hFile);
return FALSE;
}
//Create a string form of the hash (used later in pszMemberTag)
LPWSTR pszMemberTag = new WCHAR[dwHash * 2 + 1];
for (DWORD dw = 0; dw < dwHash; ++dw)
{
wsprintfW(&pszMemberTag[dw * 2], L"%02X", bHash[dw]);
}
if (!CryptCATAdminAcquireContext(&hCatAdmin, &DriverActionGuid, 0))
{
CloseHandle(hFile);
return FALSE;
}
//find the catalog which contains the hash
hCatInfo = CryptCATAdminEnumCatalogFromHash(hCatAdmin, bHash, dwHash, 0, NULL);
if (hCatInfo)
{
CATALOG_INFO ci = { 0 };
CryptCATCatalogInfoFromContext(hCatInfo, &ci, 0);
memset(&wci, 0, sizeof(wci));
wci.cbStruct = sizeof(WINTRUST_CATALOG_INFO);
wci.pcwszCatalogFilePath = ci.wszCatalogFile;
wci.pcwszMemberFilePath = pwszSourceFile;
wci.hMemberFile = hFile;
wci.pcwszMemberTag = pszMemberTag;
wci.pbCalculatedFileHash = bHash;
wci.cbCalculatedFileHash = dwHash;
wci.hCatAdmin = hCatAdmin;
memset(&wd, 0, sizeof(wd));
wd.cbStruct = sizeof(WINTRUST_DATA);
wd.pPolicyCallbackData = NULL;
wd.pSIPClientData = NULL;
wd.dwUIChoice = WTD_UI_NONE;
wd.fdwRevocationChecks = WTD_REVOKE_NONE;
wd.dwUnionChoice = WTD_CHOICE_CATALOG;
wd.pCatalog = &wci;
wd.dwStateAction = WTD_STATEACTION_VERIFY;
wd.hWVTStateData = NULL;
wd.pwszURLReference = NULL;
wd.dwProvFlags |= WTD_CACHE_ONLY_URL_RETRIEVAL;
wd.dwUIContext = 0;
wd.pSignatureSettings = 0;
lStatus = WinVerifyTrust((HWND)INVALID_HANDLE_VALUE, &WintrustVerifyGuid, &wd);
wd.dwStateAction = WTD_STATEACTION_CLOSE;
WinVerifyTrust((HWND)INVALID_HANDLE_VALUE, &WintrustVerifyGuid, &wd); //close hWVTStateData
CryptCATAdminReleaseCatalogContext(hCatAdmin, hCatInfo, 0);
}
CryptCATAdminReleaseContext(hCatAdmin, 0);
delete[] pszMemberTag;
CloseHandle(hFile);
}
return (lStatus == ERROR_SUCCESS);
}
int main(int argc, char *argv[])
{
if (VerifySignature(argv[1]))
printf("Verified file signature\n");
else
printf("Could not verify file signature\n");
return 0;
}

Resources