ffmpeg新版本很多接口发生了变化,因此在使用时需要确定自己的版本,在这里使用的版本为2.1。?
在此特别感谢雷博提供的相关文章:FFmpeg_雷霄骅的博客-CSDN博客
#include <iostream>
#include <stdio.h>
extern "C" {
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libavformat/avio.h"
#include <libavutil/log.h>
#include <libavutil/timestamp.h>
}
#define ERROR_STR_SIZE 1024
int main() {
int ret = -1;
int err_code;
char errors[ERROR_STR_SIZE];
AVFormatContext *ifmt_ctx = NULL;
AVCodecContext *pCodecCtx;
const AVOutputFormat *ofmt = NULL;
AVStream *in_stream1 = NULL;
int vedio_stream_indes = 0;
// 文件最大时长,保证音频和视频数据长度一致
double max_duration = 0;
AVPacket *pkt;
int stream1 = 0, stream2 = 0;
const char* video = "E:\\jiao\\project\\162300.mp4";
/*//初始化网络,如果要解封装网络数据格式,则可调用该函数。
avformat_network_init();*/
//av_register_all();//高版本已弃用
//打开输入文件(可解析视频参数)
ifmt_ctx = avformat_alloc_context();
if ((err_code = avformat_open_input(&ifmt_ctx, video, 0, 0)) != 0) {
av_strerror(err_code, errors, ERROR_STR_SIZE);
return -1;
}
if (avformat_find_stream_info(ifmt_ctx, NULL) < 0) {
printf("Couldn't find stream information.\n");
return -1;
}
// 找到视频流下标
vedio_stream_indes = -1;
for (int i = 0; i < ifmt_ctx->nb_streams; i++) {
if (ifmt_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
vedio_stream_indes = i;
break;
}
}
if (vedio_stream_indes == -1) {
printf("Didn't find a video stream");
return -1;
}
// 获取文件中的视频流
in_stream1 = ifmt_ctx->streams[vedio_stream_indes];
int rate = in_stream1->r_frame_rate.num; //视频帧率
int w = in_stream1->codecpar->width; //视频图像宽
int h = in_stream1->codecpar->height; //视频图像高
if (in_stream1->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
printf("the input is video.\n");
}
//软解码,查找解码器
const AVCodec *pCodec = avcodec_find_decoder(in_stream1->codecpar->codec_id);
if (pCodec == NULL) {
printf("Codec not found.\n");
return -1;
}
//获取编解码器上下文
pCodecCtx = avcodec_alloc_context3(pCodec);
if (pCodecCtx == NULL)
{
printf("get av codec context failed.\n");
return -1;
}
//设置编解码器上下文参数
if (avcodec_parameters_to_context(pCodecCtx, in_stream1->codecpar) < 0) {
printf("set param failed!\n");
return -1;
}
//打开编解码器
if (avcodec_open2(pCodecCtx, pCodec, NULL) != 0) {
printf("Could not open codec.\n");
return -1;
}
AVFrame *frame;
//frame 初始化
frame = av_frame_alloc();
pkt = av_packet_alloc();
int frames = 0;
while (av_read_frame(ifmt_ctx, pkt)>=0) {
if (pkt->stream_index == vedio_stream_indes) {
//解封装,将包发送到解码队列中
ret = avcodec_send_packet(pCodecCtx, pkt);
if (ret < 0) {
continue;
}
if (ret >= 0) {
ret = avcodec_receive_frame(pCodecCtx, frame);
int keyfrmae = frame->key_frame; //是否为I帧
printf("keyframe:%d\n", keyfrmae);
if (ret == 0) {
frames += 1;
//printf("decodec sucess.\n");
printf("frames:%d\n",frames);
} else {
printf("receive failed.\n");
}
}
}
av_packet_unref(pkt); //必须要有,否则每帧解码av_read_frame都会产生堆内存,造成内存泄漏
}
av_free(frame->data);
avcodec_free_context(&pCodecCtx);
avformat_free_context(ifmt_ctx);
av_packet_free(&pkt);
return 1;
}
视频解码方法在rtsp流解码同样适用。?
AVDictionary *options = NULL;
av_dict_set(&options, "rtsp_transport", "tcp", 0);
avformat_open_input(&ifmt_ctx, rtsp, 0, &options)
使用tcp传输方式获取数据?
ffmpeg解码出来的图像转为opencv可以使用的Mat类数据 (BGR格式)
#include <opencv2/core.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>
using namespace cv;
SwsContext *swsContext = sws_getContext(w, h, pCodecCtx->pix_fmt, w, h, AV_PIX_FMT_BGR24,
SWS_BICUBIC, NULL, NULL, NULL);
AVFrame *pFrameBGR = NULL;
uint8_t *out_bufferBGR = NULL;
pFrameBGR = av_frame_alloc();
//给pFrameBGR帧加上分配的内存;
out_bufferBGR = new uint8_t[w*h*3];
av_image_fill_arrays(pFrameBGR->data, pFrameBGR->linesize,
out_bufferBGR, AV_PIX_FMT_BGR24, w, h, 1);
sws_scale(swsContext, frame->data, frame->linesize, 0,
pCodecCtx->height, pFrameBGR->data, pFrameBGR->linesize);
Mat img(frame->height, frame->width, CV_8UC3, out_bufferBGR);
imshow("show", img);
waitKey(1);
av_free(pFrameBGR->data);
delete [] out_bufferRGB; //一定要使用delete[],而不是delete
sws_freeContext(swsContext); //释放内存
|