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>