#include
#include
#include
#include
#include
int main(int argc, char *argv[]) {
AVFormatContext *pFormatCtx = NULL;
int videoStreamIndex;
AVCodecContext *pCodecCtx = NULL;
AVCodec *pCodec = NULL;
AVFrame *pFrame = NULL;
AVPacket packet;
struct SwsContext *sws_ctx = NULL;
SDL_Window *window = NULL;
SDL_Renderer *renderer = NULL;
SDL_Texture *texture = NULL;
SDL_Event event;
int quit = 0;
// Initialize FFmpeg
av_register_all();
// Open video file
if (avformat_open_input(&pFormatCtx, argv[1], NULL, NULL) != 0) {
fprintf(stderr, "Could not open file.n");
return -1;
}
// Retrieve stream information
if (avformat_find_stream_info(pFormatCtx, NULL) < 0) {
fprintf(stderr, "Could not find stream information.n");
return -1;
}
// Find the first video stream
videoStreamIndex = -1;
for (int i = 0; i < pFormatCtx->nb_streams; i++) {
if (pFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
videoStreamIndex = i;
break;
}
}
if (videoStreamIndex == -1) {
fprintf(stderr, "Could not find video stream.n");
return -1;
}
// Get a pointer to the codec context for the video stream
pCodecCtx = avcodec_alloc_context3(NULL);
avcodec_parameters_to_context(pCodecCtx, pFormatCtx->streams[videoStreamIndex]->codecpar);
// Find the decoder for the video stream
pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
if (pCodec == NULL) {
fprintf(stderr, "Unsupported codec.n");
return -1;
}
// Open codec
if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0) {
fprintf(stderr, "Could not open codec.n");
return -1;
}
// Allocate video frame
pFrame = av_frame_alloc();
// Initialize SDL
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
fprintf(stderr, "Could not initialize SDL - %sn", SDL_GetError());
return -1;
}
// Create a window
window = SDL_CreateWindow("Video Player", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, pCodecCtx->width, pCodecCtx->height, SDL_WINDOW_SHOWN);
if (window == NULL) {
fprintf(stderr, "Could not create window - %sn", SDL_GetError());
return -1;
}
// Create a renderer
renderer = SDL_CreateRenderer(window, -1, 0);
if (renderer == NULL) {
fprintf(stderr, "Could not create renderer - %sn", SDL_GetError());
return -1;
}
// Create a texture
texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_YV12, SDL_TEXTUREACCESS_STREAMING, pCodecCtx->width, pCodecCtx->height);
if (texture == NULL) {
fprintf(stderr, "Could not create texture - %sn", SDL_GetError());
return -1;
}
// Read frames and display them
while (av_read_frame(pFormatCtx, &packet) >= 0) {
// Is this a packet from the video stream?
if (packet.stream_index == videoStreamIndex) {
// Decode video frame
int response = avcodec_send_packet(pCodecCtx, &packet);
if (response < 0) {
fprintf(stderr, "Error while sending a packet to the decoder: %sn", av_err2str(response));
return response;
}
while (response >= 0) {
response = avcodec_receive_frame(pCodecCtx, pFrame);
if (response == AVERROR(EAGAIN) || response == AVERROR_EOF) {
break;
} else if (response < 0) {
fprintf(stderr, "Error while receiving a frame from the decoder: %sn", av_err2str(response));
return response;
}
// Convert the image from its native format to YUV
sws_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height, AV_PIX_FMT_YUV420P, SWS_BILINEAR, NULL, NULL, NULL);
AVFrame *pFrameYUV = av_frame_alloc();
uint8_t *buffer = (uint8_t *)av_malloc(av_image_get_buffer_size(AV_PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height, 1) * sizeof(uint8_t));
av_image_fill_arrays(pFrameYUV->data, pFrameYUV->linesize, buffer, AV_PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height, 1);
sws_scale(sws_ctx, (uint8_t const * const *)pFrame->data, pFrame->linesize, 0, pCodecCtx->height, pFrameYUV->data, pFrameYUV->linesize);
// Update the texture
SDL_UpdateYUVTexture(texture, NULL, pFrameYUV->data[0], pFrameYUV->linesize[0], pFrameYUV->data[1], pFrameYUV->linesize[1], pFrameYUV->data[2], pFrameYUV->linesize[2]);
// Free the YUV frame
av_free(buffer);
av_frame_free(&pFrame