[ffmpeg]解码并显示

本文介绍了一个使用FFmpeg和SDL2实现的简单视频播放器示例代码。该程序能够打开并播放指定路径下的视频文件,通过FFmpeg解码视频流,并利用SDL2进行渲染。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

//
//  main.cpp
//  ffmpeg03
//
//  Created by 史明 on 16/11/3.
//  sminger1202@gmail.com
//  gcc main.c -lavformat -lavcodec `pkg-config --cflags --libs sdl2`  -o main.out
//  compile on mac OS X EI capitan 10.11.6 as following.
//  gcc main.cpp  `pkg-config --cflags --libs  libavcodec libavformat  sdl2` -o out.out
//  Copyright © 2016年 史明. All rights reserved.
//

#include <stdio.h>

#define __STDC_CONSTANT_MACROS

#ifdef _WIN32
//Windows
extern "C"
{
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libswscale/swscale.h"
#include "libavutil/imgutils.h"
#include "SDL2/SDL.h"
};
#else
//Linux...
#ifdef __cplusplus
extern "C"
{
#endif
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
#include <libavutil/imgutils.h>
#include <SDL2/SDL.h>
#ifdef __cplusplus
};
#endif
#endif

const char path[] = "/Users/shiming/ffmpegResearch/FFmpeg-Tutorial/ss1-part.mp4";
//const char path[] = "/Users/shiming/Downloads/independent.rmvb";
int main(int argc, const char * argv[]) {
    // insert code here...
    int errCode = -1;
    int videoStreamID = -1;
    AVFormatContext *pAVFmtCtx;
    AVCodecContext *pAVCodecCtx;
    AVCodec *pAVCodec;
    AVCodecParameters *pAVCodecPars;
    AVFrame *pAVFrame;
    AVPacket *pAVPacket;
    //SDL 相关

    int screen_w,screen_h;
    SDL_Window *screen;
    SDL_Renderer* sdlRenderer;
    SDL_Texture* sdlTexture;


    //std::cout << "Hello, World!\n";
    //注册编解码器和一些其他的东西
    av_register_all();
    //打开流媒体
    if((errCode = avformat_open_input(&pAVFmtCtx, path, NULL, NULL) < 0)) {
        printf("open input file fail! err code :%d", errCode);
        return errCode;
    }

    //获取流媒体信息
    if((errCode = avformat_find_stream_info(pAVFmtCtx, NULL)) < 0) {
        printf("find input file info fail! err code :%d", errCode);
        return errCode;
    }

    //dump the info of media file onto standard err
    av_dump_format(pAVFmtCtx, 0, path, 0);


    for (int i = 0; i < pAVFmtCtx->nb_streams; ++i) {
        if (AVMEDIA_TYPE_VIDEO == pAVFmtCtx->streams[i]->codecpar->codec_type) {
            printf("video stream id : %d\n", i);
            videoStreamID = i;
        }
    }
    if (videoStreamID == -1) {
        printf("find stream id failed!");
        return -1;
    }
    pAVCodecPars = pAVFmtCtx->streams[videoStreamID]->codecpar;

    //寻找解码器,并申请解码器的上下文
    pAVCodec = avcodec_find_decoder(pAVCodecPars->codec_id);
    pAVCodecCtx = avcodec_alloc_context3(pAVCodec);
    if((errCode = avcodec_parameters_to_context(pAVCodecCtx, pAVCodecPars)) < 0) {
        printf("copy the codec parameters to context fail, err code : %d\n", errCode);
        return errCode;
    }
    //打开解码器,如果要使用av_send_frame和av_receive_frame就必须才用这种方式打开
    if((errCode = avcodec_open2(pAVCodecCtx, pAVCodec, NULL)) < 0){
        printf("open codec failed ! errcode : %d", errCode);
        return errCode;
    }

    if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER)) {
        printf("init sdl failed! -%s\n", SDL_GetError());
        return -1;
    }

    screen_h = pAVCodecPars->height;
    screen_w = pAVCodecPars->width;
    screen = SDL_CreateWindow("Player demo window", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, screen_w, screen_h, SDL_WINDOW_OPENGL);
    if (!screen) {
        printf("create window failed %s", SDL_GetError());
    }
    sdlRenderer = SDL_CreateRenderer(screen, -1, 0);
    sdlTexture = SDL_CreateTexture(sdlRenderer, SDL_PIXELFORMAT_IYUV, SDL_TEXTUREACCESS_STREAMING,pAVCodecPars->width,pAVCodecPars->height);

    pAVFrame = av_frame_alloc();
    pAVPacket = av_packet_alloc();
    int retCode = -1;
    while (av_read_frame(pAVFmtCtx, pAVPacket) >= 0) {
        if (pAVPacket->stream_index == videoStreamID) {
            retCode = avcodec_send_packet(pAVCodecCtx, pAVPacket);
            if(!retCode) {
                retCode = avcodec_receive_frame(pAVCodecCtx, pAVFrame);
                switch (retCode) {
                    case 0:
                        printf("decode a frame success\n");
                        SDL_UpdateYUVTexture( sdlTexture, NULL, pAVFrame->data[0], pAVFrame->linesize[0],
                                          pAVFrame->data[1], pAVFrame->linesize[1],
                                          pAVFrame->data[2], pAVFrame->linesize[2]);
                        SDL_RenderClear( sdlRenderer );
                        SDL_RenderCopy( sdlRenderer, sdlTexture, NULL, NULL);
                        SDL_RenderPresent( sdlRenderer );
                        SDL_Delay(40);

                        break;
                    case AVERROR_EOF:
                        printf("the decoder has been fully flushed,\
                               and there will be no more output frames.\n");
                        break;

                    case AVERROR(EAGAIN):
                        printf("Resource temporarily unavailable\n");
                        break;

                    case AVERROR(EINVAL):
                        printf("Invalid argument\n");
                        break;
                    default:
                        break;
                }
            }
        }
        av_packet_unref(pAVPacket);
    }
    SDL_Quit();

    av_free(pAVFrame);
    av_free(pAVPacket);
    avcodec_close(pAVCodecCtx);
    avformat_close_input(&pAVFmtCtx);
    return 0;
}

编译此程序前,请确保安装了SDL2,下载地址:http://www.libsdl.org/download-2.0.php
劳动可贵,欢迎转载,请注明出处~
http://blog.youkuaiyun.com/minger1202/article/details/52469056

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值