1.环境:
Ubuntu 18.04
ffmpeg版本:
ffmpeg version N-103899-g855014ff83 Copyright (c) 2000-2021 the FFmpeg developers
built with gcc 7 (Ubuntu 7.5.0-3ubuntu1~18.04)
configuration: --enable-gpl --enable-shared
libavutil 57. 7.100 / 57. 7.100
libavcodec 59. 9.101 / 59. 9.101
libavformat 59. 5.100 / 59. 5.100
libavdevice 59. 0.101 / 59. 0.101
libavfilter 8. 9.100 / 8. 9.100
libswscale 6. 1.100 / 6. 1.100
libswresample 4. 0.100 / 4. 0.100
libpostproc 56. 0.100 / 56. 0.100
2.代码:
从官方的例子decode_video.c和《最简单的基于FFMPEG+SDL的视频播放器 ver2 (采用SDL2.0)》--雷霄骅
参考编写的。解码出来的数据是YUV420的格式,对于没有安装opencv的可以写入到一个文件使用yuvplayer等工具查看,在代码的131行有。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef __cplusplus
extern "C"
{
#endif
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#ifdef __cplusplus
}
#endif
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc.hpp>
using namespace cv;
int main(int argc, char **argv)
{
const AVCodec *codec;
AVCodecContext *c= NULL;
AVFrame *frame;
AVPacket *pkt;
AVFormatContext *fmt_ctx = NULL;
char *input_filename = NULL;
int ret = 0;
int w = 0, h = 0;
uint8_t *fbuf;
if (argc != 2) {
fprintf(stderr, "usage: %s input_file\n"
"API example program to show how to read from a custom buffer "
"accessed through AVIOContext.\n", argv[0]);
exit(-1);
}
input_filename = argv[1];
if (!(fmt_ctx = avformat_alloc_context())) {
ret = AVERROR(ENOMEM);
exit(-1);
}
ret = avformat_open_input(&fmt_ctx, input_filename, NULL, NULL);
if (ret < 0) {
fprintf(stderr, "Could not open input\n");
exit(-1);
}
ret = avformat_find_stream_info(fmt_ctx, NULL);
if (ret < 0) {
fprintf(stderr, "Could not find stream information\n");
exit(-1);
}
int codecIndex = -1;
for(int i=0; i<fmt_ctx->nb_streams; i++){
if(fmt_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO){
codecIndex = i;
break;
}
}
if(codecIndex == -1){
perror("can not found codec");
exit(-1);
}
{
AVCodecParameters *cp = fmt_ctx->streams[codecIndex]->codecpar;
w = cp->width;
h = cp->height;
printf("dec width=%d height=%d\n", w, h);
fbuf = (uint8_t *)malloc(w*h*3/2);
}
av_dump_format(fmt_ctx, 0, input_filename, 0);
pkt = av_packet_alloc();
if (!pkt)
exit(1);
/* find the video decoder */
codec = avcodec_find_decoder(\
fmt_ctx->streams[codecIndex]->codecpar->codec_id);
if (!codec) {
fprintf(stderr, "Codec not found\n");
exit(1);
}
c = avcodec_alloc_context3(codec);
if (!c) {
fprintf(stderr, "Could not allocate video codec context\n");
exit(1);
}
/* open it */
if (avcodec_open2(c, codec, NULL) < 0) {
fprintf(stderr, "Could not open codec\n");
exit(1);
}
frame = av_frame_alloc();
if (!frame) {
fprintf(stderr, "Could not allocate video frame\n");
exit(1);
}
namedWindow("ts", WINDOW_NORMAL);
resizeWindow("ts", 1280, 720);
Mat src(Size(w, h*3/2), CV_8UC1, fbuf);
Mat dst(Size(w, h), CV_8UC4);
while(av_read_frame(fmt_ctx, pkt) >= 0){
if(pkt->stream_index == codecIndex){
ret = avcodec_send_packet(c, pkt);
if (ret < 0) {
fprintf(stderr, "Error sending a packet for decoding\n");
exit(1);
}
while (ret >= 0) {
ret = avcodec_receive_frame(c, frame);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
break;
else if (ret < 0) {
fprintf(stderr, "Error during decoding\n");
exit(1);
}
mempcpy(fbuf, frame->data[0], w*h);
mempcpy(fbuf+w*h, frame->data[1], w*h/4);
mempcpy(fbuf+w*h*5/4, frame->data[2], w*h/4);
#if 0
if(frame->key_frame){
FILE *f;
f = fopen("py.yuv", "wb");
fwrite(fbuf, w*h*3/2, 1, f);
fclose(f);
}
#else
cvtColor(src, dst, COLOR_YUV2BGRA_I420);
imshow("ts", dst);
waitKey(1);
#endif
}
}
}
avcodec_free_context(&c);
av_frame_free(&frame);
av_packet_free(&pkt);
return 0;
}
3.运行结果
dec width=1920 height=1088
Input #0, mpegts, from './example1.ts':
Duration: 00:02:00.00, start: 0.700000, bitrate: 12895 kb/s
Program 1
Stream #0:0[0x100]: Video: h264 (Main) ([27][0][0][0] / 0x001B), yuv420p(progressive), 1920x1088, 25.25 tbr, 90k tbn