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