EasyPlayer支持YUV数据导出功能

EasyPlayer支持YUV数据导出功能我们可能会遇到这样的功能,播放一个视频的同时,再把这个视频推送出去,或者对视频数据进行智能分析等处理.这样我们就迫切需要得到视频的原始数据.基于这个需求,EasyPlayer增加了获取视频YUV数据的功能.它的原理是这样的:CreatedwithRaphaël2.1.2EasyPlayerClientEasyPlayerClientDecoderDecoderYUVYUV读取媒体…

大家好,又见面了,我是你们的朋友全栈君。

我们可能会遇到这样的功能,播放一个视频的同时,再把这个视频推送出去,或者对视频数据进行智能分析等处理.这样我们就迫切需要得到视频的原始数据.基于这个需求,EasyPlayer增加了获取视频YUV数据的功能.
它的原理是这样的:

Created with Raphaël 2.1.2 EasyPlayerClient EasyPlayerClient Decoder Decoder YUV YUV 读取媒体流 解码,获得YUV数据,导出

一般的播放器在解码之后,直接渲染YUV视频帧,并不做导出处理.因此在实现的时候,我们需要完善第二部分的功能,即解码后的YUV数据导出来.

解码部分需要通过jni来封装给java层调用.

下面代码片段就是解码并返回YUV数据的片段:

nRet = avcodec_decode_video2(pComponent->pCodecCtx, pComponent->pFrame, &got_picture, &packet);
    av_free_packet(&packet);
    if (nRet < 0)
    {
      char av_error[AV_ERROR_MAX_STRING_SIZE] = { 0 };
        LOGI("avcodec_decode_video2 result %d %s \r\n", nRet,
            av_make_error_string(av_error, AV_ERROR_MAX_STRING_SIZE, nRet));
        return nRet;
    }
        if( got_picture)    // 解出一个视频帧了.
        {
            width = pComponent->pFrame->width;
            height = pComponent->pFrame->height;
            int size = avpicture_get_size((AVPixelFormat)pComponent->pFrame->format, width, height);
            uint8_t* buffer = NULL;
            if (*pYUV == NULL){
              buffer = (uint8_t*)av_malloc(size);
            }else{
              buffer = (uint8_t *)*pYUV;
            }
            unsigned int y = width * pComponent->pFrame->height;
            unsigned int u = width/2 * pComponent->pFrame->height / 2;
            unsigned int v = width/2 * pComponent->pFrame->height / 2;

            for (int l = 0;l<height;l++){
                memcpy(buffer + l*width, pComponent->pFrame->data[0] + pComponent->pFrame->linesize[0] * l, width);
            }

            for (int l = 0;l<height/2;l++){
                memcpy(buffer + y +  l*width/2, pComponent->pFrame->data[1] + pComponent->pFrame->linesize[1] * l, width/2);
                memcpy(buffer + y + u + l*width/2, pComponent->pFrame->data[2] + pComponent->pFrame->linesize[2] * l, width/2);
            }
            // 将视频帧付给YUV buffer.
            *pYUV = buffer;
        }

下面是调用的片段:

unsigned char *pYUV = NULL;
unsigned int width;
unsigned int height;
VIDEO_HANDLE *vh =(VIDEO_HANDLE*) handle;
int r = h264_decoder_decode(vh->handle_h264, (unsigned char *)(pBuffer + offset), size, &pYUV, width, height);
jobject buf = NULL;
if (r > 0){
  buf = pEnv->NewDirectByteBuffer(pYUV, width*height * 3/2);
}
return buf;

当解码成功后,我们创建一个DirectBuffer,将yuv数据返回到JAVA层.这样,播放器就可以获取到YUV数据了.

注意这里的pYUV数据,是我们在decoder内部开辟的,我们需要在JAVA层使用结束后,主动释放.该函数传入上个函数返回的DirectBuffer,在底层会获取到其对应的YUV 数据块,然后再释放它.

释放YUV:

JNIEXPORT void JNICALL Java_org_easydarwin_video_VideoCodec_releaseYUV(                                                                             JNIEnv *pEnv, jclass jobj, jobject buffer)
{
    void *pYUV = pEnv->GetDirectBufferAddress(buffer);
    h264_decoder_release((unsigned char *)pYUV);
}

最后,我们看看上层的调用:

// 解码
ByteBuffer buf = mDecoder.decodeFrameYUV(frameInfo, size);
// 将YUV buffer 回调给上层.
if (i420callback != null && buf != null)        i420callback.onI420Data(buf);
// 释放YUV buffer
if (buf != null) mDecoder.releaseBuffer(buf);

关于EasyPlayer流媒体播放器

An elegant, simple, fast android RTSP/RTMP/HLS/HTTP Player.EasyPlayer support RTSP(RTP over TCP/UDP)version & Pro version,cover all kinds of streaming media!EasyPlayer是一款精炼、高效、稳定的流媒体播放器,分为RTSP版、RTMP版和Pro版三个版本,支持各种各样的流媒体音视频协议和文件的播放,在安防、互联网、教育、录播、IPTV等多个领域大放异彩,广泛应用!

EasyPlayer:https://github.com/EasyDSS/EasyPlayer

点击链接加入群【EasyPlayer】:544917793

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/148942.html原文链接:https://javaforall.net

(0)
上一篇 2022年6月25日 下午10:46
下一篇 2022年6月25日 下午10:46


相关推荐

  • JavaScript零基础入门 4:javascript对象有哪些

    JavaScript零基础入门 4:javascript对象有哪些Java 学习路线配套文章 Java 学习路线总结 搬砖工逆袭 Java 架构师 全网最强 基础推荐 Java 基础教程系列 实战推荐 SpringBoot 基础教程 简介 Java 领域优质创作者 CSDN 哪吒公众号作者 Java 架构师奋斗者 扫描主页左侧二维码 加入群聊 一起学习 一起进步 欢迎点赞 收藏 留言 目录一 对象 1 对象的分类 2 创建对象 3 属性 4 读取对象中的属性 5 修改对象的属性值 6 删除对象的

    2026年3月19日
    1
  • 深度学习:Seq2seq模型

    深度学习:Seq2seq模型http blog csdn net pipisorry article details Seq2seq 模型 seq2seq 是什么 简单的说 就是根据一个输入序列 x 来生成另一个输出序列 y seq2seq 有很多的应用 例如翻译 文档摘取 问答系统等等 在翻译中 输入序列是待翻译的文本 输出序列是翻译后的文本 在问答系统中 输入序列是提出的问题 而输出序列是答案 Enc

    2026年3月19日
    2
  • md5加密算法是可逆的_md5为什么不可逆

    md5加密算法是可逆的_md5为什么不可逆md5加密以上代码输出结果:注:md5算法是不可逆的,所以经过md5加密过的字符串是无法还原(解密)的。一般用作登陆验证的时候,也是要先经过md5加密然后去数据库验证密码是否正确。据说md5是被

    2022年8月3日
    6
  • mariadb 的安装及基本配置

    mariadb 的安装及基本配置文章目录一、mariadb介绍二、mariadb下载及安装三、mariadb的启停命令四、mariadb的配置五、添加用户,设置权限Navicat连接数据库一、mariadb介绍MariaDB数据库管理系统是MySQL的一个分支,主要由开源社区在维护,采用GPL授权许可。开发这个分支的原因之一是:甲骨文公司收购了MySQL后,有将MySQL闭源的潜在风险,因此社区采用分支的方式来避开这个风险。MariaDB的目的是完全兼容MySQL,包括API和命令行,使之能轻松成为MySQL的代替品。在存储引擎

    2022年5月16日
    68
  • Python数据类型有哪些?

    Python数据类型有哪些?数据类型是每种编程语言必备属性,只有给数据赋予明确的数据类型,计算机才能对数据进行处理运算,因此,正确使用数据类型是十分必要的,不同的语言,数据类型类似,但具体表示方法有所不同,以下是Python编程常用的数据类型:1.数字类型Python数字类型主要包括int(整型)、long(长整型)和float(浮点型),但是在Python3中就不再有long类型了。int(整型)在32位…

    2022年6月10日
    35
  • Claude中文版:Claude 4国内使用指南(支持Claude-4-Opus

    Claude中文版:Claude 4国内使用指南(支持Claude-4-Opus

    2026年3月16日
    2

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号