2016-09-06 6 views
-1

私たちは、Androidプラットフォーム上でビデオフレーム抽出のためにFFMPEGライブラリを消費するプロジェクトに取り組んでいます。 WindowsではAndroidでFFMPEG APIを使用して30fpsでフレームを抽出するにはどうすればよいですか?

、我々が観察した:

  • のCLIを使用して、ffmpegのコマンドffmpeg -i input.flv -vf fps=1 out%d.pngを使用して30 fpsでフレームを抽出することができます。
  • Xugglerを使用して、30fpsでフレームを抽出することができます。
  • コードでFFMPEG APIを直接使用すると、30fpsでフレームが取得されます。

しかし、我々は、Android(See Hardware Details)、我々は次のような結果になっている上で直接FFMPEGのAPIを使用する場合:

  • 720pの映像(1280×720) - 16のFPSを(約60ミリ秒/フレーム)
  • 1080pの映像(1920×1080) - 7つのFPS(約140ミリ秒/フレーム)

は、我々はまだAndroid上でXuggler/CLIをテストしていません。

理想的には、一定の時間(約30ms /フレーム)でデータを取得できるはずです。

Androidで30fpsを取得するにはどうすればよいですか? Android上で使用されている

コード:

if (avformat_open_input(&pFormatCtx, pcVideoFile, NULL, NULL)) { 
    iError = -1; //Couldn't open file 
} 

if (!iError) { 
    //Retrieve stream information 
    if (avformat_find_stream_info(pFormatCtx, NULL) < 0) 
     iError = -2; //Couldn't find stream information 
} 

//Find the first video stream 
if (!iError) { 

    for (i = 0; i < pFormatCtx->nb_streams; i++) { 
     if (AVMEDIA_TYPE_VIDEO 
       == pFormatCtx->streams[i]->codec->codec_type) { 
      iFramesInVideo = pFormatCtx->streams[i]->nb_index_entries; 
      duration = pFormatCtx->streams[i]->duration; 
      begin = pFormatCtx->streams[i]->start_time; 
      time_base = (pFormatCtx->streams[i]->time_base.num * 1.0f) 
        /pFormatCtx->streams[i]->time_base.den; 

      pCodecCtx = avcodec_alloc_context3(NULL); 
      if (!pCodecCtx) { 
       iError = -6; 
       break; 
      } 

      AVCodecParameters params = { 0 }; 
      iReturn = avcodec_parameters_from_context(&params, 
        pFormatCtx->streams[i]->codec); 
      if (iReturn < 0) { 
       iError = -7; 
       break; 
      } 

      iReturn = avcodec_parameters_to_context(pCodecCtx, &params); 
      if (iReturn < 0) { 
       iError = -7; 
       break; 
      } 

      //pCodecCtx = pFormatCtx->streams[i]->codec; 

      iVideoStreamIndex = i; 
      break; 
     } 
    } 
} 

if (!iError) { 
    if (iVideoStreamIndex == -1) { 
     iError = -3; // Didn't find a video stream 
    } 
} 

if (!iError) { 
    // Find the decoder for the video stream 
    pCodec = avcodec_find_decoder(pCodecCtx->codec_id); 
    if (pCodec == NULL) { 
     iError = -4; 
    } 
} 

if (!iError) { 
    // Open codec 
    if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0) 
     iError = -5; 
} 

if (!iError) { 
    iNumBytes = av_image_get_buffer_size(AV_PIX_FMT_RGB24, pCodecCtx->width, 
      pCodecCtx->height, 1); 

    // initialize SWS context for software scaling 
    sws_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, 
      pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height, 
      AV_PIX_FMT_RGB24, 
      SWS_BILINEAR, 
      NULL, 
      NULL, 
      NULL); 
    if (!sws_ctx) { 
     iError = -7; 
    } 
} 
clock_gettime(CLOCK_MONOTONIC_RAW, &end); 
delta_us = (end.tv_sec - start.tv_sec) * 1000000 
     + (end.tv_nsec - start.tv_nsec)/1000; 
start = end; 
//LOGI("Starting_Frame_Extraction: %lld", delta_us); 
if (!iError) { 
    while (av_read_frame(pFormatCtx, &packet) == 0) { 
     // Is this a packet from the video stream? 
     if (packet.stream_index == iVideoStreamIndex) { 
      pFrame = av_frame_alloc(); 
      if (NULL == pFrame) { 
       iError = -8; 
       break; 
      } 

      // Decode video frame 
      avcodec_decode_video2(pCodecCtx, pFrame, &iFrameFinished, 
        &packet); 
      if (iFrameFinished) { 
       //OUR CODE 
      } 
      av_frame_free(&pFrame); 
      pFrame = NULL; 
     } 
     av_packet_unref(&packet); 
    } 
} 
+0

あなたが "30のFPS" とはどういう意味ですか?あなたがテストした 'ffmpeg'コマンドラインが与えられれば、それはよりよく理解されます。 – halfelf

+0

30 fpsとは... 10秒のビデオに300フレームあり、コマンドラインで10秒間に300フレームをディスクに抽出して保存できるとします。 'ffmpeg -i -vf fps = 30 out%d.png' –

+0

ダウン投票にはどのような理由がありますか? –

答えて

1

あなたはlibavfilterからいくつかの構造と機能を必要としています。

vfオプションは、「ビデオフィルタ」を意味します。コマンドラインffmpeg -i input -vf fps=30 out%d.pngは元のビデオfpsに関係なくvideo_length_in_seconds * 30を出力します。つまり、ビデオが25 fpsの場合、重複フレームが発生します。ビデオが30fpsを超えると、フレームが失われます。

これを達成するには、いくつかのフィルタコンテキストを初期化する必要があります。 ffmpegソースのfiltering_video.cの例を参照してください。

AVFilter* buffersrc = avfilter_get_by_name("buffer"); 
AVFilter* buffersink = avfilter_get_by_name("buffersink"); 
AVFilterInOut* outputs = avfilter_inout_alloc(); 
AVFilterInOut* inputs = avfilter_inout_alloc(); 
AVRational time_base = p_format_ctx->streams[video_stream]->time_base; 
enum AVPixelFormat pix_fmts[] = { p_codec_ctx->pix_fmt, AV_PIX_FMT_NONE }; 

filter_graph = avfilter_graph_alloc(); 
if (!outputs || !inputs || !filter_graph) { 
    // failed, goto cleanup 
} 

char args[512]; 
snprintf(args, sizeof(args), 
     "video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d", 
     p_codec_ctx->width, p_codec_ctx->height, p_codec_ctx->pix_fmt, 
     time_base.num, time_base.den, 
     p_codec_ctx->sample_aspect_ratio.num, p_codec_ctx->sample_aspect_ratio.den); 

int ret = avfilter_graph_create_filter(&buffersrc_ctx, buffersrc, "in", 
             args, NULL, filter_graph); 

if (ret < 0) { 
    LOG(ERROR) << "Cannot create buffer source"; 
    avfilter_inout_free(&inputs); 
    avfilter_inout_free(&outputs); 
    return false; 
} 

ret = avfilter_graph_create_filter(&buffersink_ctx, buffersink, "out", 
            NULL, NULL, filter_graph); 
if (ret < 0) { 
    // failed... blabla 
} 

ret = av_opt_set_int_list(buffersink_ctx, "pix_fmts", pix_fmts, 
          AV_PIX_FMT_NONE, AV_OPT_SEARCH_CHILDREN); 
if (ret < 0) { 
    // failed... blabla 
} 

outputs->name  = av_strdup("in"); 
outputs->filter_ctx = buffersrc_ctx; 
outputs->pad_idx = 0; 
outputs->next  = NULL; 

inputs->name  = av_strdup("out"); 
inputs->filter_ctx = buffersink_ctx; 
inputs->pad_idx  = 0; 
inputs->next  = NULL; 

const char* filter_description[256] = "fps=fps=30"; 

if ((ret = avfilter_graph_parse_ptr(filter_graph, filters_descr.c_str(), 
            &inputs, &outputs, NULL)) < 0) { 
    // failed... 
} 

if ((ret = avfilter_graph_config(filter_graph, NULL)) < 0) { 
    // failed... 
} 

これはすべて初期化が必要です。

とデコードの部分にいくつかのコードを追加:

avcodec_decode_video2(p_codec_ctx, p_frame, &got_frame, &packet); 
if (*got_frame) { 
    p_frame->pts = av_frame_get_best_effort_timestamp(p_frame); 
    if (av_buffersrc_add_frame_flags(buffersrc_ctx, p_frame, AV_BUFFERSRC_FLAG_KEEP_REF) < 0) { 
     // failed... blabla 
    } 
    while (1) { 
     int ret = av_buffersink_get_frame(buffersink_ctx, p_frame_stage); 
     // p_frame_stage is a AVFrame struct. Same size as p_frame. Need to allocated before. 
     if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) 
      break; 
     if (ret < 0) { 
      // something wrong. filter failed.    
     } 
     // Do something with p_frame_stage here. 
    } 
} 
+0

動作しませんでした。 –

関連する問題