Wei Dongshan Embedded Linux_3 USB Camera Monitoring_Mobile Appがビデオ録画機能を追加(2)

接続し、物品監視の魏東山埋め込まLinux_3 _機能()を記録高めるためにUSBカメラ付き携帯電話のアプリケーションは、元のアプリケーションフレームワークのための改質処理を導入し始めました

1.モジュール分割

   i)(メインモジュール)ビデオのキャプチャと再生

   ii)表示モードの切り替え

   iii)写真を撮る

   iv)ビデオ

   v)fpsディスプレイ

   vi)ビデオの閲覧と削除

第二に、各モジュールの実現

2.1(メインモジュール)ビデオのキャプチャと再生

2.1.1参考資料:

1)メインフレーム(デコード、リーディングフレーム)はLei Xiaohuaを指しますFFMPEG + SDL(SDL1.x)に基づく最も単純なビデオプレーヤーを実装するための100行のコード

      メインフレームのプロセスについては、Lei Xiaohuaの上記のブログ投稿を参照してください。ここでは繰り返しません。

2)フレーム表示、参照:AndroidはFFmpeg(2)を使用してビデオストリーミングを簡単に実現

     フレーム表示の流れは、おおよそ次のようになります。

     画像

2.2表示モードの切り替え

実装のアイデア:av_filterのscaleおよびpad関数を使用して、取得された各元のフレームに必要な4辺のパディングをスケーリングおよび取得します。

メインフレームの本体コードは、FFMPEGフィルターの使用例(ビデオのスケーリング、クロッピング、透かしなどの実装)を参照します。ここでは繰り返されません。

2つの表示モードでスケールパラメーター(およびパッドパラメーター)を切り替える方法については、最適な方法が見つかりません(テスト後、av_opt_set()はdraw_text(以下を参照:2.5 fpsディスプレイ)でのみ有効ですが、スケールとパッドでのみ有効です)無効)、

現在、一時的にダムメソッドが採用されています。

1)2つのfilter_descrテンプレート、および対応するAVFilterGraph、AVFilterContextを定義します

/ *アスペクト比表示モードを維持するために使用* / 
const  char * m_filter_descr_template = " scale =%d:%d、pad =%d:%d:%d:%d:blue、drawtext = fontfile = / sdcard / data /FreeSerif.ttf:fontsize=20:text=fps:x=(w-tw-%d):y=%d ";
 char   m_filter_descr [200];
/ *全画面表示モードの場合* / 
const  char * m_filter_descr2_template = " scale =%d:%d、pad =%d:%d:%d:%d:blue、drawtext = fontfile = / sdcard / data / FreeSerif。 ttf:fontsize = 20:text = fps:x =(w-tw-5):y = 5 ";
 char   m_filter_descr2 [200];

/ *アスペクト比表示モードを維持するために使用* /
AVFilterContext * m_buffersink_ctx1;
AVFilterContext * m_buffersrc_ctx1;
AVFilterGraph * m_filter_graph1;

/ *全画面表示モードの場合* /
AVFilterContext * m_buffersink_ctx2;
AVFilterContext * m_buffersrc_ctx2;
AVFilterGraph * m_filter_graph2;

2)初期化中に、最初にkeep_img_AR()を呼び出して、2つの表示モードに対応するfilter_descrの値を事前計算します。

int keep_img_AR(int nSrcW、int nSrcH、int nDstW、int nDstH)
{ / *上部と下部に黒い境界線がある、または黒い境界線がある左右にある幅と高さの比率、黒い境界線の数* / int imgW = 0、imgH = 0;
     int padW = 0、padH = 0; // 2の倍数に丸める必要があります。
     それ以外の場合、ffmpegはパッドの計算時にエラーを報告します:入力領域がパッド領域内にないか、サイズがゼロの 
    nDstW = nDstW / 2 * 2; 
    nDstH = nDstH / 2 * 2; 
    imgW = nSrcW * nDstH / nSrcH / 2 * 2; 
    imgH = nSrcH * nDstW / nSrcW / 2 * 2; if(imgW <nDstW){ 
        padW =(nDstW-imgW)/ 2; 
        imgH = nDstH / 2 * 2 ; // imgW = -1; 
    } else if(imgH <nDstH){
    
    

    
        
     
        padH =(nDstH-imgH)/ 2; 
        imgW = nDstW / 2 * 2; // imgH = -1; 
    } 
    sprintf(m_filter_descr、m_filter_descr_template、imgW、imgH、nDstW、nDstH、padW、padH、padW + 5、padH + 5); 
    sprintf(m_filter_descr2、m_filter_descr2_template、nDstW、nDstH、nDstW、nDstH、0、0); 1を返す ; 
}
        

    

3)次に、init_filters()を呼び出して、m_filter_graph1、m_buffersink_ctx1、m_buffersrc_ctx1およびm_filter_graph2、m_buffersink_ctx2、m_buffersrc_ctx2を初期化します。

     init_filters()のコードは、FFMPEGフィルターの使用例(ビデオスケーリング、クロッピング、透かしなどの実装)を参照します。ここでは繰り返されません。

4)再生モードを切り替えると、実際には(m_filter_graph1、m_buffersink_ctx1、m_buffersrc_ctx1)と(m_filter_graph2、m_buffersink_ctx2、m_buffersrc_ctx2)が切り替わります

/ ** 
 *プレーヤは、ビデオのアスペクト比を保持する
 * / 
ボイド playVideoKeepAspectRatio()
{ 
    m_play_video_mode = PLAY_VIDEO_KEEP_ASPECT_RATIO; 
    m_filter_graph = m_filter_graph1; 
    m_buffersrc_ctx = m_buffersrc_ctx1; 
    m_buffersink_ctx = m_buffersink_ctx1; 
} / ** 
 *再生映像表示領域を埋める
 * / ボイド playVideoFullScreen ()
{ 
    m_play_video_mode = PLAY_VIDEO_FULL_SCREEN; 
    m_filter_graph = m_filter_graph2; 
    m_buffersrc_ctx = m_buffersrc_ctx2; 
    m_buffersink_ctx = m_buffersink_ctx2; 
}


注:表示モードの切り替えに関して、これを実現する別の方法はsws_scale()およびav_picture_pad()を使用することです。参照:ffmpegのlibライブラリを使用して、ビデオウィンドウの元の幅と高さの比/ストレッチを実現します。

しかし、コードの量は多く、テスト後、次のようないくつかの問題が見つかりました。

-av_filterのdraw_textを追加した後、fps表示がわずかに上下にジャンプします。理由は調査されることです。

-fpsの配置は(パッドの幅のため)実現がより困難です。

したがって、最終的にはこのメソッドは採用されませんでした(ただし、keep_img_AR()でスケールとパッドを計算するアルゴリズムはこの記事を参照しています)。

2.3写真を撮る

実装のアイデア:

1)現在取得されているフレームを表すm_pFrameCurを定義します

2)ビデオ再生関数videoStreamStartPlay()のwhileループで、av_frame_ref(m_pFrameCur、pFrame)を使用して、m_pFrameCurが現在取得されているフレームを指すようにします。

3)__save_frame_2_jpeg(file_path、m_pFrameCur、m_input_codec_ctx-> pix_fmt)は、現在のフレームを指定されたファイルに保存します

     コード参照:ffmpegはmjpegカメラのコレクションプレビュー写真を実現します。詳細はここにありません

2.4ビデオ

リファレンス:FFmpeg APIを使用してカメラビデオとマイクオーディオを収集し、ファイルを記録する機能を実現する方法

この記事のデモでは、レコーディング関数はCAVOutputStreamクラスにうまくカプセル化されていますが、基本的にレコーディング関数の基本的な実装にはそのまま使用します。

追加した作業は、ビデオ再生関数videoStreamStartPlay()のwhileループでステートマシンvideo_capture_state_machine()を呼び出すことです。コードはおおよそ次のとおりです。

void video_capture_state_machine(AVFrame * pFrame)
{ スイッチ(m_video_capture_state)
    { ケース VIDEO_CAPTURE_START:
            LOGD( " VIDEO_CAPTURE_START "); 
            m_start_time = av_gettime(); 
            m_OutputStream.SetVideoCodec(AV_CODEC_ID_H264); //设置视频编码器属性if(true == m_OutputStream.OpenOutputStream(m_save_video_path.c_str()))
                m_video_capture_state = VIDEO_CAPTURE_IN_PROGRESS; それ以外の場合は 
                m_video_capture_state = VIDEO_CAPTURE_IDLE; 休憩 ;
        ケース VIDEO_CAPTURE_IN_PROGRESS:
            LOGD( "
    
        
            
            
            VIDEO_CAPTURE_IN_PROGRESS "); 
            m_OutputStream.write_video_frame(m_input_format_ctx->ストリーム[m_video_stream_index]、m_input_format_ctx->ストリーム[m_video_stream_index] - > codec-> pix_fmt、PFRAME、av_gettime() - m_start_time); ブレーク ;
         ケース VIDEO_CAPTURE_STOP:
            のlogD(" VIDEO_CAPTURE_STOP「) ; 
            m_OutputStream.CloseOutput(); 
            m_video_capture_state = VIDEO_CAPTURE_IDLE; break ;
         defaultif(m_video_capture_state == VIDEO_CAPTURE_IDLE){ 
                LOGD( " VIDEO_CAPTURE_IDLE "); 
            } else
            
            
            { 
                LOGD( " m_video_capture_state:%d "、m_video_capture_state); 
            } 休憩 ; 
    } // eo switch(m_video_capture_state) 
}
            

ネイティブレイヤーとJAVAレイヤーのインターフェイスは次のとおりです。

/ *开始录像* / 
void videoStreamStartCapture(const  char * file_path)
{ 
    m_save_video_path = file_path; 
    m_video_capture_state = VIDEO_CAPTURE_START; 
} / *停止画像* / void videoStreamStopCapture()
{ 
    m_video_capture_state = VIDEO_CAPTURE_STOP; 
}


2.5 fpsディスプレイ

実現の考え方は同じです:2.2表示モードの切り替え

fps値の動的な表示は、av_opt_set(filter_ctx_draw_text-> priv、 "text"、str_fps、0)を使用して実現されます。

2.6ビデオの閲覧と削除

実装のアイデア:基本的に、アプリの元のフレームワークを使用しますが、変更点はわずかです。主に次のように:

1)MainActivity.java

      ユーザーが[写真]ボタンをクリックすると、AlertDialogがポップアップし、ブラウジングのタイプを選択するように求めます。次に、ユーザーの選択に応じて、startActivity(インテント)の前に呼び出します。

      intent.putExtra( "picturePath"、picturePath);

      intent.putExtra( "scan_type"、ScanPicActivity.SCAN_TYPE_VIDEO);

      または

      intent.putExtra( "picturePath"、videoRecordPath);

      intent.putExtra( "scan_type"、ScanPicActivity.SCAN_TYPE_PIC);

2)ScanPicActivity.java

      -init()関数で、scan_type = getIntent().GetIntExtra( "scan_type"、SCAN_TYPE_PIC);現在の閲覧タイプを保存します

      ・「jpeg」の文字列が関わる箇所すべてにScan_typeを追加。コードは省略されています。詳細については、プロジェクトのソースコードを参照してください

3)Generic.java

      getShrinkedPic()を模倣し、関数getShrinkedPicFromVideo()を追加します。コアはThumbnailUtils.createVideoThumbnail()です。コードは省略されています。詳細については、プロジェクトのソースコードを参照してください

参考資料:

1)Wei Dongshan Embedded Linux Trainingフェーズ3プロジェクトの実際のUSBカメラの監視、携帯電話のアプリのソースコード

2)Android公式チュートリアル:https : //developer.android.google.cn/guide/

3)AndroidStudio3.xは、Android-NDKのC ++コードを開発してデバッグします

4)NDK開発ノート-CMakeビルドJNI

5)Lei Xiaohuaのブログシリーズの記事:[概要] FFMPEGビデオおよびオーディオコーデックのゼロベースの学習方法

6)AndroidはFFmpeg(2)を使用-ビデオストリーミングのシンプルな実現

7)FFmpeg APIを使用してカメラのビデオとマイクの音声を収集し、ファイルを記録する機能を実現する方法

8)ffmpegはmjpegカメラの収集、プレビュー、写真撮影を実現します

9)FFMPEGフィルターの例を使用する(ビデオのスケーリング、クロッピング、透かしなどを実現するため)

10)ffmpegのlibライブラリを使用して、ビデオウィンドウの元の幅と高さの比/ストレッチを実現します

11)ffmpegは字幕コンテンツの動的調整を実現します

12)Ffmpegの使用法の要約(下記)

13)Android logcatでFFmpegデバッグ情報を出力します

おすすめ

転載: www.cnblogs.com/normalmanzhao2003/p/12695432.html