1

I need to make a thumbnail for a video, to seek to the 25% of a video and save the image. Here is what I'm doing right now, but it only saves black image.

#include <stdio.h>

#include <libavformat/avformat.h>
#include <libavutil/dict.h>

int main (int argc, char **argv)
{

    av_register_all();

    AVFormatContext *pFormatCtx = avformat_alloc_context();

    int res;

    res = avformat_open_input(&pFormatCtx, "test.mp4", NULL, NULL);
    if (res) {
        return res;
    }


    avformat_find_stream_info(pFormatCtx, NULL);

    int64_t duration = pFormatCtx->duration;


    // Find the first video stream
    int videoStream=-1;
    for(int i=0; i<pFormatCtx->nb_streams; i++) {
        if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO) {
            videoStream=i;
            break;
        }
    }
    if(videoStream==-1) {
        return -1;
    }

    AVCodecContext *pCodecCtxOrig = NULL;

    // Get a pointer to the codec context for the video stream
    pCodecCtxOrig=pFormatCtx->streams[videoStream]->codec;


    AVCodec *pCodec = NULL;
    // Find the decoder for the video stream
    pCodec=avcodec_find_decoder(pCodecCtxOrig->codec_id);
    if(pCodec==NULL) {
        fprintf(stderr, "Unsupported codec!\n");
        return -1; // Codec not found
    }


    AVCodecContext *pCodecCtx = NULL;
    // Copy context
    pCodecCtx = avcodec_alloc_context3(pCodec);
    if(avcodec_copy_context(pCodecCtx, pCodecCtxOrig) != 0) {
        fprintf(stderr, "Couldn't copy codec context");
        return -1; // Error copying codec context
    }


    // Open codec
    if(avcodec_open2(pCodecCtx, pCodec, NULL)<0) {
        return -1; // Could not open codec
    }


    AVFrame *pFrame = NULL;

    pFrame=av_frame_alloc();

    AVFrame *pFrameRGB = NULL;

    pFrameRGB=av_frame_alloc();



    // Determine required buffer size and allocate buffer
    int numBytes=avpicture_get_size(AV_PIX_FMT_RGB24, pCodecCtx->width,
                                pCodecCtx->height);

    uint8_t *buffer = NULL;
    buffer=(uint8_t *)av_malloc(numBytes*sizeof(uint8_t));


    // Assign appropriate parts of buffer to image planes in pFrameRGB
    // Note that pFrameRGB is an AVFrame, but AVFrame is a superset
    // of AVPicture
    res = avpicture_fill((AVPicture *)pFrameRGB, buffer, AV_PIX_FMT_RGB24,
                    pCodecCtx->width, pCodecCtx->height);
    if (res<0) {
        return;
    }



    // I've set this number randomly
    res = av_seek_frame(pFormatCtx, videoStream, 20.0, AVSEEK_FLAG_FRAME);
    if (res<0) {
        return;
    }



    AVPacket packet;
    while(1) {
        av_read_frame(pFormatCtx, &packet);
        if(packet.stream_index==videoStream) {
            int frameFinished;
            avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet);
            if(frameFinished) {
                SaveFrame(pFrameRGB, pCodecCtx->width,
                    pCodecCtx->height);
                break;
            }

        }
    }


    avformat_close_input(&pFormatCtx);
    return 0;
}



void SaveFrame(AVFrame *pFrame, int width, int height) {
  FILE *pFile;
  char szFilename[] = "frame.ppm";
  int  y;

  // Open file
  pFile=fopen(szFilename, "wb");
  if(pFile==NULL)
    return;

  // Write header
  fprintf(pFile, "P6\n%d %d\n255\n", width, height);

  // Write pixel data
  for(y=0; y<height; y++)
    fwrite(pFrame->data[0]+y*pFrame->linesize[0], 1, width*3, pFile);

  // Close file
  fclose(pFile);
}

I was following this tutorial http://dranger.com/ffmpeg/tutorial01.html http://dranger.com/ffmpeg/tutorial07.html . It says that it was updated in 2015, but there already are some warnings about deprecated code, for example here: pFormatCtx->streams[i]->codec.

I got video duration (in microseconds), but I don't understand what I should send to av_seek_frame. Can I somehow use frame number for both duration and seeking, instead of time?

puppon -su
  • 137
  • 2
  • 8

1 Answers1

0

Here is an article about av_seek_frame:

Also, you never set pFrameRGB to a new value after you initialized it using avpicture_fill.

You possibly might just change to this:

 avcodec_decode_video2(pCodecCtx, pFrameRGB, &frameFinished, &packet);

Additionally i am not sure if your current code guarantees that you even deal with an RGB stream, you might need to color-convert it...

Harry
  • 1,233
  • 10
  • 24