FFmpegのピクセルフォーマット変換(YUV回転RGB)ディスプレイと使用SurfaceView

免責事項:この記事はブロガーオリジナル記事ですが、許可ブロガーなく再生してはなりません。https://blog.csdn.net/myvest/article/details/90717333

1、FFmpegのピクセルフォーマット変換

FFmpegの画素変換は、一般libswscaleに使用されています

インターフェイス説明

図1に示すように、取得コンテキストSwsContextが
以前に作成した幅/高さ/一定の入力及び出力フォーマット、コンテキストが返された場合、一般的に我々が入手するには、次の二つの機能を使用し、sws_getCachedContext sws_getContextは、わずかに異なっていると。
パラメータ:
最初の3つのパラメータは、元の幅、高さ、形式(例えばRGBA8888、YUV420、等)に分割なり、幅のパラメータ3つの変換され、高いフォーマット後、flagsパラメータを指定するために使用される変換アルゴリズムを、最後の三つNULLは、パラメータとして指定することができます。

struct SwsContext *sws_getContext(int srcW, int srcH, enum AVPixelFormat srcFormat,
                                  int dstW, int dstH, enum AVPixelFormat dstFormat,
                                  int flags, SwsFilter *srcFilter,
                                  SwsFilter *dstFilter, const double *param);
struct SwsContext *sws_getCachedContext(struct SwsContext *context,
                                        int srcW, int srcH, enum AVPixelFormat srcFormat,
                                        int dstW, int dstH, enum AVPixelFormat dstFormat,
                                        int flags, SwsFilter *srcFilter,
                                        SwsFilter *dstFilter, const double *param);

2、伝達関数sws_scaleの
パラメータ:
パラメータ構造体SwsContextの*のC:コンテキスト。
パラメータCONST uint8_tの*のCONST srcSlice []:入力データ、データポインタ、各チャンネルのデータポイント。一般的には、パラメータとしてフレーム- >データからデコード。
パラメータCONST INT srcStride []:行あたりのバイトのチャンネル番号。一般的には、このパラメータとしてフレーム- >行サイズでデコードすることができます。

ストライドは、次の行の先頭を定義します。ストライド幅と必ずしも同一、理由:
1)によりフレームに格納されたアライメントデータに、そこ=跨ぐようなパディングバイトの数を増加幅+ N各行の後に得る;
2)パケット色空間、いくつかの各ピクセル次の行の位置は、3つの*幅バイトをスキップする必要があるように、データチャネルは、3バイトの行に格納された画素ごとに、例えばRGB24、一緒に混合されます。
srcSlice同じ寸法とsrcFormat値にsrcStride。

CSP维数の宽幅跨度YUV420 3ワット、高歩幅
W / 2、W / 2 S、S / 2、S / 2H、H / 2、H / 2 YUYV / 2 W / 2 wで、
2S、 0、0、H、H、HのNV12 2 W、W / 2、W / 2 S、S、0
H、H / 2 RGB24 1、3S wは、0、0時間、0 wで、0

パラメータINT srcSliceY、INT srcSliceH:入力画像領域、srcSliceY開始位置、srcSliceH何ライン処理に定義処理。srcSliceY = 0の場合、srcSliceH =高さ、使い捨て処理に全体像を示します。
例えば、二つのスレッドを作成し、するために、この構成は、第一のスレッド処理[0、H / 2-1]線、第二の処理スレッド[H / 2、H-1マルチスレッド平行である ] ライン。並列処理速度。

パラメータuint8_t * CONSTのDST []、CONSTは INT dstStride [] 定義する出力画像情報(各チャンネルのデータ出力ポインタは、各チャネルのオクテット数)
画素の出力に基づいて、これら2つのパラメータがav_image_alloc使用することができ得るが、あることができます自己定義された形式。

int sws_scale(struct SwsContext *c, const uint8_t *const srcSlice[],
              const int srcStride[], int srcSliceY, int srcSliceH,
              uint8_t *const dst[], const int dstStride[]);

3、リリース機能

void sws_freeContext(struct SwsContext *swsContext);

int FFDecoder::videoConvert(AVFrame* pFrame, uint8_t* out){
    if(pFrame == NULL || out == NULL) 
        return 0;
    
    //AVPicture pict;
    //av_image_alloc(pict.data, pict.linesize, pVCodecCxt->width,pVCodecCxt->height, AV_PIX_FMT_RGBA, 16);
    uint8_t* dst_data[4] = {0};
    char *swsData = new char[720*576*4];
    dst_data[0] =(uint8_t *)swsData;
    
    int dst_linesize[4];
    dst_linesize[0] =  720*4;
    swsContext = sws_getCachedContext(swsContext,pFrame->width, pFrame->height,(AVPixelFormat)pFrame->format,
                                      720, 576, AV_PIX_FMT_RGBA, SWS_FAST_BILINEAR, 0, 0, 0);
    if(swsContext){
        sws_scale(swsContext, (const uint8_t**)pFrame->data, pFrame->linesize, 0, pFrame->height, (uint8_t* const*)dst_data, dst_linesize);
        size_t size = dst_linesize[0] * 576;
        memcpy(out,dst_data[0],size);
        //av_free(&pict.data[0]);
        return size;
    }
    
    //av_free(&pict.data[0]);
    return 0;
}

2、SurfaceViewを用いたディスプレイ

JAVAは、C ++層は、我々はC ++層を使用しているが実際のAndroid ANativeWindowを処理するために使用されることもあり、映像データは、SurfaceView表示層処理を使用して変換されます。
だから我々は、表面を通って表示するようにJNI層にANativeWindowを得るために、JNI層に渡された表面を得た後、JAVA層SurfaceViewを作成する必要があります。

JAVAのSurfaceViewを作成した層、及び入射面:
表面がsurfaceChangedまたはsurfaceCreatedコールバック関数で、作成されていることを確認するには、それがダウンして設定することが表面化します。
言うまでもなく作成SurfaceView、あなたはレイアウトファイルに関連するコントロールを追加することができます。
次のように:

    private void initView() {
      mSurfaceView = (SurfaceView)findViewById(R.id.surfaceView); 
      mSurfaceHolder = mSurfaceView.getHolder();
      mSurfaceHolder.addCallback(new Callback() {
      
		@Override
		public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
			if(mFFdec != null){
				mFFdec.initSurface(mSurfaceHolder.getSurface());
			}
		}
		@Override
		public void surfaceCreated(SurfaceHolder arg0) {}
		@Override
		public void surfaceDestroyed(SurfaceHolder arg0) {}
		});
    }
    

mFFdec.initSurface(mSurfaceHolder.getSurface());ネイティブインタフェースは、次のように具体的に実現さJNI表面層に設けられています。

public  native void initSurface(Surface surface);

......仅列出关键代码
static ANativeWindow* g_nwin = NULL;
static void jni_initSurface(JNIEnv* env, jobject obj, jobject surface){
	if(surface){
		g_nwin = ANativeWindow_fromSurface(env, surface);
		if(g_nwin){
			ANativeWindow_setBuffersGeometry(g_nwin, 720, 576, WINDOW_FORMAT_RGBA_8888);
			LOGE("jni_initSurface g_nwin[%p],g_nwin->perform[%p]\n",g_nwin,g_nwin->perform);
		}
	}
    return;
}

static JNINativeMethod gMethods[] = {
    {"decodeInit", "()V", (void*)jni_decodeInit},
    {"decodeDeInit", "()V", (void*)jni_decodeDeInit},
    {"decodeFrame", "([B)I", (void*)jni_decodeFrame},
    {"openInput", "(Ljava/lang/String;)I", (void*)jni_openInput},
    {"getMediaSampleRate", "()I", (void*)jni_getMediaSampleRate},
    {"getMediaType", "()I", (void*)jni_getMediaType},
    {"initSurface", "(Landroid/view/Surface;)V", (void*)jni_initSurface},
};
...省略

ANativeWindow使用方法

1.初期化:
ANativeWindow JAVA入射面層から取得した呼び出しANativeWindow_fromSurfaceは、
幅/高さ/ピクセルフォーマットを含め、ANativeWindow ANativeWindow_setBuffersGeometryパラメータを設定コール(と、私たちは、着信データと一致するように注意を払います)。
図2に示すように、ロック:
ANativeWindowは、ダブルバッファリング機構、第一呼ANativeWindow_lockロックバッファ背景の一部であり、バッファ表面のアドレスを取得します。
3、ドロー:
バッファデータを埋めるために、すなわち、バッファのロックを解除して描き、ANativeWindow_unlockAndPostを呼び出します。

static int renderVframe(uint8_t* rgb,int size){
    if(g_nwin == NULL)
        return -1;

    LOGE("renderVframe g_nwin[%p],g_nwin->perform[%p]\n",g_nwin,g_nwin->perform);
    ANativeWindow_Buffer outBuffer;

    ANativeWindow_lock(g_nwin, &outBuffer,0);//获取surface缓冲区的地址
    uint8_t* dst = (uint8_t*)outBuffer.bits;
    memcpy(dst,rgb,size);//往surface缓冲区填充显示的RGB内容
    ANativeWindow_unlockAndPost(g_nwin);

    return 0;
}

おすすめ

転載: blog.csdn.net/myvest/article/details/90717333