使用ffmpeg+opencv播放ts格式的视频

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

  • 7
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值