從視訊中不斷抓取圖檔的基本流程:打開視訊流位址->擷取視訊流packt->解碼成圖檔幀->輸出圖檔
一.初始化Ffmpeg
void ffmpegInit()
{
av_register_all();
avformat_network_init();
av_log_set_level(AV_LOG_ERROR);
}
如果你不想輸出log,設定log級别為AV_LOG_PANIC。
二.打開視訊。
int Open(char* url)
{
context = avformat_alloc_context();
context->interrupt_callback.opaque = this; //C++
context->interrupt_callback.callback = interruptCallback;//設定回調函數,否則有可能ffmpeg一直被挂住。
context->start_time_realtime = av_gettime();
AVDictionary* options = nullptr;
av_dict_set(&options, "rtsp_transport", "udp", 0); //以udp方式打開,如果以tcp方式打開将udp替換為tcp
av_dict_set(&options, "stimeout", "3000000", 0); //設定逾時斷開連接配接時間
int ret = avformat_open_input(&context, url, nullptr, &options); //avformat_open_input 傳回0表示open成功,小于0表示open失敗
if(ret < 0) return ret;
ret = avformat_find_stream_info(context, options); ///avformat_find_stream_info 傳回0表示查抄stream info成功 小于0表示失敗。
if(options!= nullptr)
{
av_dict_free(options);
}
return ret;
}
int interrupt_cb(void *ctx)
{
if((av_gettime() - ffmpeg->lastFrameRealtime) > 10 * 1000 * 1000) //10s逾時退出
{
return AVERROR_EOF;
}
return 0;
}
三 .讀取視訊包:
shared_ptr<AVPacket> ReadPacket()
{
shared_ptr<AVPacket> packet((AVPacket*)av_malloc(sizeof(AVPacket)), [&](AVPacket *p){av_free_packet(p);av_freep(&p);});
av_init_packet(packet.get());
lastFrameRealtime = av_gettime();
int ret = av_read_frame(context, packet.get());
if(ret >= 0)
{
return packet;
}
else
{
return nullptr;
}
}
說明一下:不一定要用智能指針。我确定這樣寫不會有記憶體洩露,是以就不改了,随手寫的代碼會有bug。
四. 解碼
1. 初始化解碼器
InitDecoderCodec
{
int ret = -1;
for(int i = 0; i < context->nb_streams; ++i)
{
AVCodecContext *codecContext = context->streams[i]->codec;
if(codecContext->codec_type == AVMEDIA_TYPE_VIDEO)
{
//傳回小于0,打開解碼器失敗
ret = avcodec_open2(codecContext, avcodec_find_decoder(codecContext->codec_id), &options);
}
}
return ret;
}
2. 解碼視訊包
AVFrame* DecodeVideoPacket(AVCodecContext* codecContext)
{
AVFrame* videoFrame = av_frame_alloc();
auto hr = avcodec_decode_video2(codecContext, frame, &gotFrame, packet);
if(hr >= 0 && gotFrame != 0)
{
return videoFrame;
}
else
{
avcodec_free_frame(&videoFrame);
return nullptr
}
}
輸出圖檔:
uint8_t *GetPictureData(int width,int height, int *bufferSize)
{
pFrameYUV= av_frame_alloc();
uint8_t *out_buffer;
out_buffer = new uint8_t[avpicture_get_size(PIX_FMT_RGB32, width, height)];
avpicture_fill((AVPicture *)pFrameYUV, out_buffer, PIX_FMT_RGB32, width, height);
sws_scale(sws, (const uint8_t* const*)frame->data, frame->linesize, 0, height, pFrameYUV->data, pFrameYUV->linesize);
*bufferSize = width * height * 4;
return pFrameYUV->data[0];
}
context是全局變量,如果有問題,加群流媒體/Ffmpeg/音視訊 127903734或者766718184進行交流
視訊下載下傳位址:http://www.chungen90.com/?news_33/
Demo下載下傳位址: http://www.chungen90.com/?news_34