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>
相关推荐
xcLeigh3 小时前
HTML5实现好看的视频播放器(三种风格,附源码)
前端·音视频·html5
别动哪条鱼3 小时前
SDL 函数对各对象缓冲区的影响
网络·数据结构·ffmpeg
骄傲的心别枯萎6 小时前
RV1126 NO.57:ROCKX+RV1126人脸识别推流项目之读取人脸图片并把特征值保存到sqlite3数据库
数据库·opencv·计算机视觉·sqlite·音视频·rv1126
好游科技6 小时前
IM即时通讯系统:安全可控、功能全面的社交解决方案全解析
安全·音视频·webrtc·im即时通讯·私有化部署im即时通讯·社交app
EasyDSS7 小时前
视频直播点播平台EasyDSS构建高并发、低延迟的远程教学直播新模式
音视频
GIOTTO情7 小时前
多模态舆情监测技术深度解析:Infoseek 如何实现 AI 造假与短视频舆情的精准捕捉?
人工智能·音视频
音视频牛哥7 小时前
C# 开发工业级 RTSP/RTMP 播放器实战:基于 SmartMediakit 的低延迟与高可靠性设计
音视频·rtsp播放器·rtmp播放器·windows rtsp播放器·windows rtmp播放器·c# rtsp播放器·c# rtmp播放器
JellyDDD7 小时前
【悬赏】Android WebRTC 数字人项目回声问题排查(AEC / AudioMode)
音视频·webrtc
于是我说8 小时前
如何判断一个视频到底是真实 MP4 直链,还是流媒体M3U8
网络·音视频
gf13211119 小时前
剪映草稿位置坐标换算
音视频