FFmpeg 视频播放demo

sourcecode

main.c

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#include <libswscale/swscale.h>
#include <libavutil/imgutils.h>
#include <SDL2/SDL.h>
#include <signal.h>
#include <stdbool.h>

// 全局标志变量,用于指示程序是否应该退出
volatile sig_atomic_t exit_program = false;

// 信号处理函数
void handle_sigint(int sig) {
    if (sig == SIGINT) {
        printf("Caught SIGINT, exiting...\n");
        exit_program = true;
    }
}

int main(int argc, char* argv[]) {
    if (argc < 2) {
        printf("Usage: %s <video_file>\n", argv[0]);
        return -1;
    }

    const char *filename = argv[1];

     // 注册信号处理函数
    signal(SIGINT, handle_sigint);

    avformat_network_init();

    // Open video file
    AVFormatContext *pFormatCtx = avformat_alloc_context();
    if (avformat_open_input(&pFormatCtx, filename, NULL, NULL) != 0) {
        printf("Couldn't open file.\n");
        return -1;
    }

    // Retrieve stream information
    if (avformat_find_stream_info(pFormatCtx, NULL) < 0) {
        printf("Couldn't find stream information.\n");
        return -1;
    }

    // Find the first video stream
    int videoStream = -1;
    for (int i = 0; i < pFormatCtx->nb_streams; i++) {
        if (pFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
            videoStream = i;
            break;
        }
    }
    if (videoStream == -1) {
        printf("Didn't find a video stream.\n");
        return -1;
    }

    // Get a pointer to the codec context for the video stream
    AVCodecParameters *pCodecPar = pFormatCtx->streams[videoStream]->codecpar;
    AVCodec *pCodec = (AVCodec*)avcodec_find_decoder(pCodecPar->codec_id);
    if (pCodec == NULL) {
        printf("Unsupported codec!\n");
        return -1;
    }

    AVCodecContext *pCodecCtx = avcodec_alloc_context3(pCodec);
    if (avcodec_parameters_to_context(pCodecCtx, pCodecPar) < 0) {
        printf("Couldn't copy codec context.\n");
        return -1;
    }

    // Open codec
    if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0) {
        printf("Couldn't open codec.\n");
        return -1;
    }

    // Allocate video frame
    AVFrame *pFrame = av_frame_alloc();
    AVFrame *pFrameRGB = av_frame_alloc();
    if (pFrameRGB == NULL || pFrame == NULL) {
        printf("Couldn't allocate frames.\n");
        return -1;
    }

    int numBytes = av_image_get_buffer_size(AV_PIX_FMT_RGB24, pCodecCtx->width, pCodecCtx->height, 32);
    uint8_t *buffer = (uint8_t *)av_malloc(numBytes * sizeof(uint8_t));
    av_image_fill_arrays(pFrameRGB->data, pFrameRGB->linesize, buffer, AV_PIX_FMT_RGB24, pCodecCtx->width, pCodecCtx->height, 32);

    struct SwsContext *sws_ctx = sws_getContext(
        pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt,
        pCodecCtx->width, pCodecCtx->height, AV_PIX_FMT_RGB24,
        SWS_BILINEAR, NULL, NULL, NULL);

    SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER);
    SDL_Window *screen = SDL_CreateWindow(
        "FFmpeg Video Playback",
        SDL_WINDOWPOS_UNDEFINED,
        SDL_WINDOWPOS_UNDEFINED,
        pCodecCtx->width,
        pCodecCtx->height,
        SDL_WINDOW_OPENGL);

    if (!screen) {
        printf("SDL: could not create window - exiting:%s\n", SDL_GetError());
        return -1;
    }

    SDL_Renderer *renderer = SDL_CreateRenderer(screen, -1, 0);
    SDL_Texture *texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGB24, SDL_TEXTUREACCESS_STREAMING, pCodecCtx->width, pCodecCtx->height);

    while (!exit_program) {
      AVPacket packet;
      int response;

      // Read frames and save first five frames to disk
      while (av_read_frame(pFormatCtx, &packet) >= 0) {
        if (packet.stream_index == videoStream) {
          response = avcodec_send_packet(pCodecCtx, &packet);
          if (response < 0) {
            printf("Error while sending a packet to the decoder.\n");
            break;
          }

          while (response >= 0) {
            response = avcodec_receive_frame(pCodecCtx, pFrame);
            if (response == AVERROR(EAGAIN) || response == AVERROR_EOF) {
              break;
            } else if (response < 0) {
              printf("Error while receiving a frame from the decoder.\n");
              return -1;
            }

            sws_scale(sws_ctx, (uint8_t const *const *)pFrame->data,
                      pFrame->linesize, 0, pCodecCtx->height, pFrameRGB->data,
                      pFrameRGB->linesize);

            SDL_UpdateTexture(texture, NULL, pFrameRGB->data[0],
                              pFrameRGB->linesize[0]);
            SDL_RenderClear(renderer);
            SDL_RenderCopy(renderer, texture, NULL, NULL);
            SDL_RenderPresent(renderer);
            SDL_Delay(40); // 25 fps
          }
        }
        av_packet_unref(&packet);
        // 检查SDL事件
        SDL_Event event;
        while (SDL_PollEvent(&event)) {
          if (event.type == SDL_QUIT) {
            exit_program = true;
          }
        }

        if (exit_program) {
          break;
        }
      }
      if (exit_program) {
        break;
      }
    }

    // Free resources
    av_free(buffer);
    av_frame_free(&pFrameRGB);
    av_frame_free(&pFrame);
    avcodec_free_context(&pCodecCtx);
    avformat_close_input(&pFormatCtx);
    sws_freeContext(sws_ctx);

    SDL_DestroyTexture(texture);
    SDL_DestroyRenderer(renderer);
    SDL_DestroyWindow(screen);
    SDL_Quit();

    return 0;
}

dependence

安装 FFmpeg 开发库:

sh

sudo apt-get install libavformat-dev libavcodec-dev libswscale-dev libavutil-dev

安装 SDL2 开发库:

sh

sudo apt-get install libsdl2-dev

compile

gcc -o  video_player main.c  -lavformat -lavcodec -lswscale -lavutil -lSDL2

run

./video_player <video_file>
相关推荐
9527华安3 小时前
FPGA实现PCIE3.0视频采集转10G万兆UDP网络输出,基于XDMA+GTH架构,提供工程源码和技术支持
网络·fpga开发·udp·音视频·xdma·pcie3.0·万兆网
电子科技圈3 小时前
XMOS携手合作伙伴晓龙国际联合推出集成了ASRC等功能的多通道音频板
科技·嵌入式硬件·mcu·物联网·音视频·iot
oushaojun23 小时前
ubuntu中使用ffmpeg和nginx推流rtmp视频
nginx·ubuntu·ffmpeg·rtmp
码码哈哈0.04 小时前
免费的视频混剪综合处理工具介绍与下载
音视频
莫固执,朋友4 小时前
网络抓包工具tcpdump 在海思平台上的编译使用
网络·ffmpeg·音视频·tcpdump
深海呐4 小时前
Android 从本地选择视频,用APP播放或进行其他处理
android·音视频·从本地选择视频,用app播放·从本地选择视频,并拿到信息·跳转到本地视频列表
lxkj_20245 小时前
修改ffmpeg实现https-flv内容加密
网络协议·https·ffmpeg
cuijiecheng20185 小时前
音视频入门基础:MPEG2-TS专题(6)——FFmpeg源码中,获取MPEG2-TS传输流每个transport packet长度的实现
ffmpeg·音视频
安静读书8 小时前
Java解析视频FPS(帧率)、分辨率信息
java·python·音视频
VisionX Lab10 小时前
数据脱敏工具:基于 FFmpeg 的视频批量裁剪
python·ffmpeg·音视频