2017-10-28 11 views
0

ビデオのサムネイルを作成し、ビデオの25%を探して画像を保存する必要があります。ここに私が今やっていることがありますが、黒い画像しか保存しません。ビデオの途中から画像を保存する方法は?

#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); 
} 

私はこのチュートリアルhttp://dranger.com/ffmpeg/tutorial01.htmlhttp://dranger.com/ffmpeg/tutorial07.htmlに従っていました。それは2015年に更新されたと言われていますが、廃止予定のコードに関する警告があります。例えば、pFormatCtx->streams[i]->codecです。

ビデオ期間(マイクロ秒単位)がありますが、av_seek_frameに送信する内容がわかりません。時間の代わりに時間とシークの両方に何とかフレーム番号を使用できますか?ここで

答えて

0

がav_seek_frameについての記事です。また

あなたはavpicture_fill使用して初期化した後、あなたは新しい値にpFrameRGBを設定することはありません。

あなたはおそらくこれだけに変更される可能性があります:

さらに
avcodec_decode_video2(pCodecCtx, pFrameRGB, &frameFinished, &packet); 

私は確認していない、あなたの現在のコードは、あなたも、RGBのストリームを扱うことが保証された場合、あなたがする必要があるかもしれません...

それをカラー変換
関連する問題