从视频中不断抓取图片的基本流程:打开视频流地址->获取视频流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。
四. 解码
- 初始化解码器
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;
}
- 解码视频包
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/?list_53
Demo下载地址: http://www.chungen90.com/?list_52
原文链接: https://www.cnblogs.com/wanggang123/p/5592350.html
欢迎关注
微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍
原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/235319
非原创文章文中已经注明原地址,如有侵权,联系删除
关注公众号【高性能架构探索】,第一时间获取最新文章
转载文章受原作者版权保护。转载请注明原作者出处!