
YUV420是指:Y : UV = 4 : 1
YUV420P是指:YUV的排列方法,先将Y排列完,再将U排列完,最后将
V排列完。如:

YYYYYYYYYYYYYYYY UUUU VVVV
FFmpeg解码出来的视频YUV数据是存储在AVFrame中的data里面,我们以
YUV420P为视频数据帮OPenGL渲染。

Y分量:frame->data[0]
U分量:frame->data[1]
V分量:frame->data[2]

绝大多数视频都是YUV420P格式的,对于不是YUV420P格式的万能播放器java版,我们先将
其转换(sws_scale)为YUV420P后再帮OPenGL ES渲染万能播放器java版,所以C++层要调用Java的OpenGL ES渲染YUV数据。
Java层

/**
*JfPlayer.java
* @param width
* @param height
* @param y
* @param u
* @param v
*/
public void onCallRenderYUV(int width,int height,byte[] y,byte[] u,byte[] v){
JfLog.d("获取到视频的数据");
}
C++层
jmid_renderyuv = env->GetMethodID(jlz, "onCallRenderYUV", "(II[B[B[B)V");
void WlCallJava::onCallRenderYUV(int width, int height, uint8_t *fy, uint8_t *fu, uint8_t *fv) {
JNIEnv *jniEnv;
if(javaVM->AttachCurrentThread(&jniEnv, 0) != JNI_OK)
{
if(LOG_DEBUG)
{
LOGE("call onCallComplete worng");
}
return;
}
jbyteArray y = jniEnv->NewByteArray(width * height);
jniEnv->SetByteArrayRegion(y, 0, width * height, reinterpret_cast<const jbyte *>(fy));
jbyteArray u = jniEnv->NewByteArray(width * height / 4);
jniEnv->SetByteArrayRegion(u, 0, width * height / 4, reinterpret_cast<const jbyte *>(fu));
jbyteArray v = jniEnv->NewByteArray(width * height / 4);
jniEnv->SetByteArrayRegion(v, 0, width * height / 4, reinterpret_cast<const jbyte *>(fv));
jniEnv->CallVoidMethod(jobj, jmid_renderyuv, width, height, y, u, v);
jniEnv->DeleteLocalRef(y);
jniEnv->DeleteLocalRef(u);
jniEnv->DeleteLocalRef(v);
javaVM->DetachCurrentThread();
}
格式转换后渲染
if (avFrame->format == AV_PIX_FMT_YUV420P){
//直接渲染
LOGD("YUV420P");
video->callJava->onCallRenderYUV(
CHILD_THREAD,
video->pVCodecCtx->width,
video->pVCodecCtx->height,
avFrame->data[0],
avFrame->data[1],
avFrame->data[2]);
} else {
//转成YUV420P
AVFrame *pFrameYUV420P = av_frame_alloc();
int num = av_image_get_buffer_size(AV_PIX_FMT_YUV420P,video->pVCodecCtx->width,video->pVCodecCtx->height,1);
uint8_t *buffer = (uint8_t *)(av_malloc(num * sizeof(uint8_t)));
av_image_fill_arrays(
pFrameYUV420P->data,
pFrameYUV420P->linesize,
buffer,
AV_PIX_FMT_YUV420P,
video->pVCodecCtx->width,
video->pVCodecCtx->height,
1);
SwsContext *sws_ctx = sws_getContext(
video->pVCodecCtx->width,
video->pVCodecCtx->height,
video->pVCodecCtx->pix_fmt,
video->pVCodecCtx->width,
video->pVCodecCtx->height,
AV_PIX_FMT_YUV420P,
SWS_BICUBIC,
NULL,NULL,NULL
);
if (!sws_ctx){
av_frame_free(&pFrameYUV420P);
av_free(pFrameYUV420P);
av_free(buffer);
continue;
}
sws_scale(
sws_ctx,
avFrame->data,
avFrame->linesize,
0,
avFrame->height,
pFrameYUV420P->data,
pFrameYUV420P->linesize);//这里得到YUV数据
LOGD("NO_YUV420P");
//渲染
video->callJava->onCallRenderYUV(
CHILD_THREAD,
video->pVCodecCtx->width,
video->pVCodecCtx->height,
pFrameYUV420P->data[0],
pFrameYUV420P->data[1],
pFrameYUV420P->data[2]);
av_frame_free(&pFrameYUV420P);
av_free(pFrameYUV420P);
av_free(buffer);
sws_freeContext(sws_ctx);
}
到此处就早已受到YUV数据了!
本文来自电脑杂谈,转载请注明本文网址:
https://www.pc-fly.com/a/bofangqi/article-135615-1.html
他有颜而不止于此