接続し、物品監視の魏東山埋め込ま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 ; default: if(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 ++コードを開発してデバッグします
5)Lei Xiaohuaのブログシリーズの記事:[概要] FFMPEGビデオおよびオーディオコーデックのゼロベースの学習方法
6)AndroidはFFmpeg(2)を使用-ビデオストリーミングのシンプルな実現
7)FFmpeg APIを使用してカメラのビデオとマイクの音声を収集し、ファイルを記録する機能を実現する方法
8)ffmpegはmjpegカメラの収集、プレビュー、写真撮影を実現します
9)FFMPEGフィルターの例を使用する(ビデオのスケーリング、クロッピング、透かしなどを実現するため)