#include <stdio.h> #include <stdlib.h> #include <libavformat/avformat.h> #include <libavcodec/avcodec.h> #include <libavutil/imgutils.h> // Function prototypes int save_frame_as_jpeg(AVFrame *pFrame, int width, int height, const char *filename); int main(int argc, char *argv[]) { if (argc < 3) { printf("Usage: %s <filename> <timestamp(ms)>\n", argv[0]); return -1; } const char *filename = argv[1]; int64_t timestamp = atoll(argv[2]); av_register_all(); AVFormatContext *pFormatContext = avformat_alloc_context(); if (!pFormatContext) { printf("Could not allocate memory for Format Context\n"); return -1; } if (avformat_open_input(&pFormatContext, filename, NULL, NULL) != 0) { printf("Could not open the file\n"); return -1; } if (avformat_find_stream_info(pFormatContext, NULL) < 0) { printf("Could not get the stream info\n"); return -1; } int video_stream_index = -1; AVCodecParameters *pCodecParameters = NULL; for (int i = 0; i < pFormatContext->nb_streams; i++) { if (pFormatContext->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { video_stream_index = i; pCodecParameters = pFormatContext->streams[i]->codecpar; break; } } if (video_stream_index == -1) { printf("Could not find video stream in the input file\n"); return -1; } AVCodec *pCodec = avcodec_find_decoder(pCodecParameters->codec_id); if (!pCodec) { printf("Could not find the codec\n"); return -1; } AVCodecContext *pCodecContext = avcodec_alloc_context3(pCodec); if (!pCodecContext) { printf("Could not allocate memory for Codec Context\n"); return -1; } if (avcodec_parameters_to_context(pCodecContext, pCodecParameters) < 0) { printf("Could not copy codec params to codec context\n"); return -1; } if (avcodec_open2(pCodecContext, pCodec, NULL) < 0) { printf("Could not open codec\n"); return -1; } AVFrame *pFrame = av_frame_alloc(); if (!pFrame) { printf("Could not allocate memory for AVFrame\n"); return -1; } int64_t timestamp_in_stream_timebase = av_rescale_q(timestamp, AV_TIME_BASE_Q, pFormatContext->streams[video_stream_index]->time_base); av_seek_frame(pFormatContext, video_stream_index, timestamp_in_stream_timebase, AVSEEK_FLAG_BACKWARD); AVPacket *packet = av_packet_alloc(); if (!packet) { printf("Could not allocate memory for AVPacket\n"); return -1; } int frame_finished = 0; while (av_read_frame(pFormatContext, packet) >= 0) { if (packet->stream_index == video_stream_index) { avcodec_send_packet(pCodecContext, packet); if (avcodec_receive_frame(pCodecContext, pFrame) == 0) { save_frame_as_jpeg(pFrame, pCodecContext->width, pCodecContext->height, "output.jpg"); break; } } av_packet_unref(packet); } av_packet_free(&packet); av_frame_free(&pFrame); avcodec_free_context(&pCodecContext); avformat_close_input(&pFormatContext); return 0; } int save_frame_as_jpeg(AVFrame *pFrame, int width, int height, const char *filename) { AVCodecContext *pJpegCodecContext = NULL; AVCodec *pJpegCodec = NULL; AVPacket packet; int ret; pJpegCodec = avcodec_find_encoder(AV_CODEC_ID_MJPEG); if (!pJpegCodec) { printf("Could not find JPEG codec\n"); return -1; } pJpegCodecContext = avcodec_alloc_context3(pJpegCodec); if (!pJpegCodecContext) { printf("Could not allocate JPEG codec context\n"); return -1; } pJpegCodecContext->pix_fmt = AV_PIX_FMT_YUVJ420P; pJpegCodecContext->height = height; pJpegCodecContext->width = width; pJpegCodecContext->time_base = (AVRational){1, 25}; if (avcodec_open2(pJpegCodecContext, pJpegCodec, NULL) < 0) { printf("Could not open JPEG codec\n"); return -1; } av_init_packet(&packet); packet.data = NULL; packet.size = 0; ret = avcodec_send_frame(pJpegCodecContext, pFrame); if (ret < 0) { printf("Error sending frame to codec context\n"); return ret; } ret = avcodec_receive_packet(pJpegCodecContext, &packet); if (ret < 0) { printf("Error receiving packet from codec context\n"); return ret; } FILE *JPEGFile = fopen(filename, "wb"); if (!JPEGFile) { printf("Could not open JPEG file\n"); return -1; } fwrite(packet.data, 1, packet.size, JPEGFile); fclose(JPEGFile); av_packet_unref(&packet); avcodec_free_context(&pJpegCodecContext); return 0; }