流媒体程序开发之:H264解码器移植到OPhone

本文涉及的产品
阿里云百炼推荐规格 ADB PostgreSQL,4核16GB 100GB 1个月
简介: 1.   移植目标        将H.264解码器移植到OPhone操作系统之上(NDK+C),并写一个测试程序(OPhoneSDK+Java)测试解码库是否正常运行,下面是解码时的截图:         OPhone的模拟器和Mobile的模拟器一样是模拟ARM指令的,不像Symbian模拟器一样执行的是本地代码,所以在模拟器上模拟出来的效率会比 真实手机上的效率要低,之前这款解码器已经优化到在nokia 6600(相当低端的一款手机,CPU主频才120Hz)上做到在线播放。
1.   移植目标
       将H.264解码器移植到OPhone操作系统之上(NDK+C),并写一个测试程序(OPhoneSDK+Java)测试解码库是否正常运行,下面是解码时的截图:


        OPhone的模拟器和Mobile的模拟器一样是模拟ARM指令的,不像Symbian模拟器一样执行的是本地代码,所以在模拟器上模拟出来的效率会比 真实手机上的效率要低,之前这款解码器已经优化到在nokia 6600(相当低端的一款手机,CPU主频才120Hz)上做到在线播放。
 

2. 面向人群
       本文面向有一定的手机应用开发经验(例如:S60/Mobile/MTK)和有一定的跨手机平台移植经验的人员,帮助她们了解一个企业的核心库(C/C++)是怎么移植到OPhone之上的。
 

3. 假定前提
1)熟悉Java/C/C++语言;
2)熟悉Java的JNI技术;
3)有一定的跨手机平台移植经验;
4)有一套可供移植的源代码库,这里以H.264解码库为例,为了保护我们的知识版权,这里只能够公开头文件:
  

  1. #ifndef __H264DECODE_H__  
  2. #define __H264DECODE_H__  
  3.   
  4. #if defined(__SYMBIAN32__)  //S602rd/3rd/UIQ  
  5.     #include <e32base.h>  
  6.     #include <libc"stdio.h>  
  7.     #include <libc"stdlib.h>  
  8.     #include <libc"string.h>  
  9. #else                       //Windows/Mobile/MTK/OPhone  
  10.     #include <stdio.h>  
  11.     #include <stdlib.h>  
  12.     #include <string.h>  
  13. #endif  
  14.   
  15. class H264Decode  
  16. {  
  17. public:  
  18.     /***************************************************************************/  
  19.     /* 构造解码器                                                        */  
  20.     /* @return H264Decode解码器实例                                      */  
  21.     /***************************************************************************/  
  22.     static H264Decode *H264DecodeConstruct();  
  23.     /***************************************************************************/  
  24.     /* 解码一帧                                                     */  
  25.     /* @pInBuffer   指向H264的视频流                                      */  
  26.     /* @iInSize H264视频流的大小                                      */  
  27.     /* @pOutBuffer  解码后的视频视频                                        */  
  28.     /* @iOutSize    解码后的视频大小                                        */  
  29.     /* @return      已解码的H264视频流的尺寸                              */  
  30.     /***************************************************************************/  
  31.     int DecodeOneFrame(unsigned char *pInBuffer,unsigned int iInSize,unsigned char *pOutBuffer,unsigned int &iOutSize);  
  32.     ~H264Decode();  
  33. };  
  34. #endif  // __H264DECODE_H__  

      你不用熟悉OPhone平台,一切从零开始,因为在此之前,我也不熟悉。
 

4.  开发环境(请参考: http://www.ophonesdn.com/documentation/)
 

5.  移植过程

5.1 移植流程

5.2 封装Java接口

        在“假定前提”中提到了要移植的函数,接下来会编写这些 函数的Java Native Interface。

  1. package ophone.streaming.video.h264;  
  2.   
  3. import java.nio.ByteBuffer;  
  4.   
  5. public class H264decode {  
  6.       
  7. //H264解码库指针,因为Java没有指针一说,所以这里用一个32位的数来存放指针的值  
  8.     private long H264decode = 0;  
  9.       
  10.     static{     
  11.         System.loadLibrary("H264Decode");  
  12.     }  
  13.   
  14.     public H264decode() {  
  15.         this.H264decode = Initialize();  
  16.     }  
  17.       
  18.     public void Cleanup() {  
  19.         Destroy(H264decode);  
  20.     }  
  21.       
  22.     public int DecodeOneFrame(ByteBuffer pInBuffer,ByteBuffer pOutBuffer) {  
  23.         return DecodeOneFrame(H264decode, pInBuffer, pOutBuffer);  
  24.     }  
  25.   
  26.     private native static int DecodeOneFrame(long H264decode,ByteBuffer pInBuffer,ByteBuffer pOutBuffer);  
  27.     private native static long Initialize();  
  28.     private native static void Destroy(long H264decode);  
  29. }  


         这块没什么好说的,就是按照H264解码库的函数,封装的一层接口,如果你熟悉Java JNI,会发现原来是这么类似。这里插入一句:我一直认为技术都是相通的,底层的技术就那么几种,学懂了,其它技术都是一通百通。

5.3 使用C实现本地方法

5.3.1生成头文件

        使用javah命令生成JNI头文件,这里需要注意是class路径不是源代码的路径,并且要加上包名:

        这里生成了一个ophone_streaming_video_h264_H264decode.h,我们打开来看看:

  1. #include <jni.h>  
  2.   
  3. #ifndef _Included_ophone_streaming_video_h264_H264decode  
  4. #define _Included_ophone_streaming_video_h264_H264decode  
  5. #ifdef __cplusplus  
  6. extern "C" {  
  7. #endif  
  8.   
  9. JNIEXPORT jint JNICALL Java_ophone_streaming_video_h264_H264decode_DecodeOneFrame  
  10.   (JNIEnv *, jclass, jlong, jobject, jobject);  
  11.   
  12. JNIEXPORT jlong JNICALL Java_ophone_streaming_video_h264_H264decode_Initialize  
  13.   (JNIEnv *, jclass);  
  14.   
  15. JNIEXPORT void JNICALL Java_ophone_streaming_video_h264_H264decode_Destroy  
  16.   (JNIEnv *, jclass, jlong);  
  17.   
  18. #ifdef __cplusplus  
  19. }  
  20. #endif  
  21. #endif  

5.3.2 实现本地方法

        之前已经生成了JNI头文件,接下来只需要实现这个头文件的几个导出函数,这里以H264解码器的实现为例:

  1. #include "ophone_streaming_video_h264_H264decode.h"  
  2. #include "H264Decode.h"  
  3.   
  4. JNIEXPORT jint JNICALL Java_ophone_streaming_video_h264_H264decode_DecodeOneFrame  
  5.   (JNIEnv * env, jclass obj, jlong decode, jobject pInBuffer, jobject pOutBuffer) {  
  6.   
  7.     H264Decode *pDecode = (H264Decode *)decode;  
  8.     unsigned char *In = NULL;unsigned char *Out = NULL;  
  9.     unsigned int InPosition = 0;unsigned int InRemaining = 0;unsigned int InSize = 0;  
  10.     unsigned int OutSize = 0;  
  11.     jint DecodeSize = -1;  
  12.   
  13.     jbyte *InJbyte = 0;  
  14.     jbyte *OutJbyte = 0;  
  15.   
  16.     jbyteArray InByteArrary = 0;  
  17.     jbyteArray OutByteArrary = 0;  
  18.   
  19.     //获取Input/Out ByteBuffer相关属性  
  20.     {  
  21.         //Input  
  22.         {  
  23.             jclass ByteBufferClass = env->GetObjectClass(pInBuffer);  
  24.             jmethodID PositionMethodId = env->GetMethodID(ByteBufferClass,"position","()I");  
  25.             jmethodID RemainingMethodId = env->GetMethodID(ByteBufferClass,"remaining","()I");  
  26.             jmethodID ArraryMethodId = env->GetMethodID(ByteBufferClass,"array","()[B");  
  27.               
  28.             InPosition = env->CallIntMethod(pInBuffer,PositionMethodId);  
  29.             InRemaining = env->CallIntMethod(pInBuffer,RemainingMethodId);  
  30.             InSize = InPosition + InRemaining;  
  31.               
  32.             InByteArrary = (jbyteArray)env->CallObjectMethod(pInBuffer,ArraryMethodId);  
  33.           
  34.             InJbyte = env->GetByteArrayElements(InByteArrary,0);  
  35.               
  36.             In = (unsigned char*)InJbyte + InPosition;  
  37.         }  
  38.   
  39.         //Output  
  40.         {  
  41.             jclass ByteBufferClass = env->GetObjectClass(pOutBuffer);  
  42.             jmethodID ArraryMethodId = env->GetMethodID(ByteBufferClass,"array","()[B");  
  43.             jmethodID ClearMethodId = env->GetMethodID(ByteBufferClass,"clear","()Ljava/nio/Buffer;");  
  44.               
  45.             //清理输出缓存区  
  46.             env->CallObjectMethod(pOutBuffer,ClearMethodId);  
  47.   
  48.             OutByteArrary = (jbyteArray)env->CallObjectMethod(pOutBuffer,ArraryMethodId);  
  49.             OutJbyte = env->GetByteArrayElements(OutByteArrary,0);  
  50.   
  51.             Out = (unsigned char*)OutJbyte;  
  52.         }  
  53.     }  
  54.   
  55.     //解码  
  56.     DecodeSize = pDecode->DecodeOneFrame(In,InRemaining,Out,OutSize);  
  57.   
  58.     //设置Input/Output ByteBuffer相关属性  
  59.     {  
  60.         //Input  
  61.         {  
  62.             jclass ByteBufferClass = env->GetObjectClass(pInBuffer);  
  63.             jmethodID SetPositionMethodId = env->GetMethodID(ByteBufferClass,"position","(I)Ljava/nio/Buffer;");  
  64.               
  65.             //设置输入缓冲区偏移  
  66.             env->CallObjectMethod(pInBuffer,SetPositionMethodId,InPosition + DecodeSize);  
  67.         }  
  68.   
  69.         //Output  
  70.         {  
  71.             jclass ByteBufferClass = env->GetObjectClass(pOutBuffer);  
  72.             jmethodID SetPositionMethodId = env->GetMethodID(ByteBufferClass,"position","(I)Ljava/nio/Buffer;");  
  73.   
  74.             //设置输出缓冲区偏移  
  75.             env->CallObjectMethod(pOutBuffer,SetPositionMethodId,OutSize);  
  76.         }  
  77.     }  
  78.   
  79.     //清理  
  80.     env->ReleaseByteArrayElements(InByteArrary,InJbyte,0);  
  81.     env->ReleaseByteArrayElements(OutByteArrary,OutJbyte,0);  
  82.   
  83.     return DecodeSize;  
  84. }  
  85.   
  86. JNIEXPORT jlong JNICALL Java_ophone_streaming_video_h264_H264decode_Initialize  
  87.   (JNIEnv * env, jclass obj) {  
  88.   
  89.     H264Decode *pDecode = H264Decode::H264DecodeConstruct();  
  90.     return (jlong)pDecode;  
  91. }  
  92.   
  93. JNIEXPORT void JNICALL Java_ophone_streaming_video_h264_H264decode_Destroy  
  94.   (JNIEnv * env, jclass obj, jlong decode) {  
  95.   
  96.     H264Decode *pDecode = (H264Decode *)decode;  
  97.     if (pDecode)  
  98.     {  
  99.         delete pDecode;  
  100.         pDecode = NULL;  
  101.     }  
  102. }  

 5.3.3 编译本地方法

        接下来,只需要把用C实现的本地方法编译为动态链接库,如果之前你用于移植的那个库曾经移植到Symbian上过,那么编译会相当简单,因为NDK的编译器和Symbian的编译器一样,都是采用GCC做交叉编译器。

        首先,需要在$NDK"apps目录下,创建一个项目目录,这里创建了一个H264Decode目录,在H264Decode目录中,创建一个Android.mk文件:
 

  1. APP_PROJECT_PATH := $(call my-dir)  
  2. APP_MODULES      := H264Decode  


       接下来,需要在$NDK"source目录下,创建源代码目录(这里的目录名要和上面创建的项目目录文件名相同),这里创建一个H264Decode目录,然后把之前生成的JNI头文件和你实现的本地方法相关头文件和源代码,都拷贝到   这个目录下面。

          然后,我们编辑Android.mk文件:

  1. LOCAL_PATH := $(call my-dir)  
  2. include $(CLEAR_VARS)  
  3. LOCAL_MODULE    := H264Decode  
  4. LOCAL_SRC_FILES := common.c cabac.c utils.c golomb.c mpegvideo.c mem.c imgconvert.c h264decode.cpp h264.c dsputil.c ophone_streaming_video_h264_H264decode.cpp  
  5. include $(BUILD_SHARED_LIBRARY)  


        关于Android.mk文件中,各个字段的解释,可以参考$NDK"doc下的《OPHONE-MK.TXT》和《OVERVIEW.TXT》,里面有详细的介绍。

        最后,我们启动Cygwin,开始编译:

       如果你看到了Install:**,这说明你的库已经编译好了。

       FAQ 2:
       如果编译遇到下面错误,怎么办?

  1. error: redefinition of typedef 'int8_t'  

   需要注释掉你的代码中“typedef signed char  int8_t;”,如果你的代码之前是已经移植到了Mobile/Symbian上的话,很有可能遇到这个问题。
       

5.4 编写库测试程序

    用Eclipse创建一个OPhone工程,在入口类中输入如下代码:

  1. /**    
  2.  * @author ophone 
  3.  * @email 3751624@qq.com 
  4.  */  
  5.   
  6. package ophone.streaming.video.h264;  
  7.   
  8. import java.io.File;  
  9. import java.io.FileInputStream;  
  10. import java.io.InputStream;  
  11. import java.nio.ByteBuffer;  
  12. import OPhone.app.Activity;  
  13. import OPhone.graphics.BitmapFactory;  
  14. import OPhone.os.Bundle;  
  15. import OPhone.os.Handler;  
  16. import OPhone.os.Message;  
  17. import OPhone.widget.ImageView;  
  18. import OPhone.widget.TextView;  
  19.   
  20. public class H264Example extends Activity {  
  21.       
  22.     private static final int VideoWidth = 352;  
  23.     private static final int VideoHeight = 288;  
  24.       
  25.     private ImageView ImageLayout = null;  
  26.     private TextView FPSLayout = null;  
  27.     private H264decode Decode = null;  
  28.     private Handler H = null;  
  29.     private byte[] Buffer = null;  
  30.       
  31.     private int DecodeCount = 0;  
  32.     private long StartTime = 0;  
  33.   
  34.     public void onCreate(Bundle savedInstanceState) {  
  35.           
  36.         super.onCreate(savedInstanceState);  
  37.         setContentView(R.layout.main);  
  38.           
  39.         ImageLayout = (ImageView) findViewById(R.id.ImageView);  
  40.         FPSLayout = (TextView) findViewById(R.id.TextView);  
  41.         Decode = new H264decode();  
  42.           
  43.         StartTime = System.currentTimeMillis();  
  44.           
  45.         new Thread(new Runnable(){  
  46.             public void run() {  
  47.                 StartDecode();  
  48.             }  
  49.         }).start();  
  50.           
  51.         H = new Handler(){  
  52.             public void handleMessage(Message msg) {  
  53.                 ImageLayout.invalidate();  
  54.                 ImageLayout.setImageBitmap(BitmapFactory.decodeByteArray(Buffer, 0, Buffer.length));  
  55.                   
  56.                 long Time = (System.currentTimeMillis()-StartTime)/1000;  
  57.                 if(Time > 0){  
  58.                     FPSLayout.setText("花费时间:" + Time + "秒  解码帧数:" + DecodeCount + "  FPS:" + (DecodeCount/Time) );  
  59.                 }  
  60.             }  
  61.         };  
  62.     }  
  63.       
  64.     private void StartDecode(){  
  65.           
  66.         File h264file = new File("/tmp/Demo.264");  
  67.         InputStream h264stream = null;  
  68.         try {  
  69.               
  70.             h264stream = new FileInputStream(h264file);  
  71.             ByteBuffer pInBuffer = ByteBuffer.allocate(51200);//分配50k的缓存  
  72.             ByteBuffer pRGBBuffer = ByteBuffer.allocate(VideoWidth*VideoHeight*3);  
  73.               
  74.             while (h264stream.read(pInBuffer.array(), pInBuffer.position(), pInBuffer.remaining()) >= 0) {  
  75.                   
  76.                 pInBuffer.position(0);  
  77.                 do{  
  78.                     int DecodeLength = Decode.DecodeOneFrame(pInBuffer, pRGBBuffer);  
  79.                       
  80.                     //如果解码成功,把解码出来的图片显示出来  
  81.                     if(DecodeLength > 0 && pRGBBuffer.position() > 0){  
  82.                           
  83.                         //转换RGB字节为BMP  
  84.                         BMPImage bmp = new BMPImage(pRGBBuffer.array(),VideoWidth,VideoHeight);  
  85.                         Buffer = bmp.getByte();  
  86.               
  87.                         H.sendMessage(H.obtainMessage());  
  88.   
  89.                         Thread.sleep(1);  
  90.                         DecodeCount ++;  
  91.                     }  
  92.                       
  93.                 }while(pInBuffer.remaining() > 10240);//确保缓存区里面的数据始终大于10k  
  94.                   
  95.                 //清理已解码缓冲区  
  96.                 int Remaining = pInBuffer.remaining();  
  97.                 System.arraycopy(pInBuffer.array(), pInBuffer.position(), pInBuffer.array(), 0, Remaining);  
  98.                 pInBuffer.position(Remaining);  
  99.             }  
  100.               
  101.         } catch (Exception e1) {  
  102.             e1.printStackTrace();  
  103.         } finally {  
  104.             try{h264stream.close();} catch(Exception e){}  
  105.         }  
  106.           
  107.     }  
  108.   
  109.     protected void onDestroy() {  
  110.         super.onDestroy();  
  111.         Decode.Cleanup();  
  112.     }  
  113. }  

      BMPImage是一个工具类,主要用于把RGB序列,转换为BMP图象用于显示:

  1. @author ophone  
  2.  * @email 3751624@qq.com  
  3. */  
  4.   
  5. package ophone.streaming.video.h264;  
  6.   
  7. import java.nio.ByteBuffer;  
  8.   
  9. public class BMPImage {  
  10.   
  11.     // --- 私有常量  
  12.     private final static int BITMAPFILEHEADER_SIZE = 14;  
  13.     private final static int BITMAPINFOHEADER_SIZE = 40;  
  14.   
  15.     // --- 位图文件标头  
  16.     private byte bfType[] = { 'B', 'M' };  
  17.     private int bfSize = 0;  
  18.     private int bfReserved1 = 0;  
  19.     private int bfReserved2 = 0;  
  20.     private int bfOffBits = BITMAPFILEHEADER_SIZE + BITMAPINFOHEADER_SIZE;  
  21.   
  22.     // --- 位图信息标头  
  23.     private int biSize = BITMAPINFOHEADER_SIZE;  
  24.     private int biWidth = 176;  
  25.     private int biHeight = 144;  
  26.     private int biPlanes = 1;  
  27.     private int biBitCount = 24;  
  28.     private int biCompression = 0;  
  29.     private int biSizeImage = biWidth*biHeight*3;  
  30.     private int biXPelsPerMeter = 0x0;  
  31.     private int biYPelsPerMeter = 0x0;  
  32.     private int biClrUsed = 0;  
  33.     private int biClrImportant = 0;  
  34.       
  35.     ByteBuffer bmpBuffer = null;  
  36.       
  37.     public BMPImage(byte[] Data,int Width,int Height){  
  38.         biWidth = Width;  
  39.         biHeight = Height;  
  40.           
  41.         biSizeImage = biWidth*biHeight*3;  
  42.         bfSize = BITMAPFILEHEADER_SIZE + BITMAPINFOHEADER_SIZE + biWidth*biHeight*3;  
  43.         bmpBuffer = ByteBuffer.allocate(BITMAPFILEHEADER_SIZE + BITMAPINFOHEADER_SIZE + biWidth*biHeight*3);  
  44.           
  45.         writeBitmapFileHeader();  
  46.         writeBitmapInfoHeader();  
  47.         bmpBuffer.put(Data);  
  48.     }  
  49.       
  50.     public byte[] getByte(){  
  51.         return bmpBuffer.array();  
  52.     }  
  53.       
  54.     private byte[] intToWord(int parValue) {  
  55.   
  56.         byte retValue[] = new byte[2];  
  57.   
  58.         retValue[0] = (byte) (parValue & 0x00FF);  
  59.         retValue[1] = (byte) ((parValue >> 8) & 0x00FF);  
  60.   
  61.         return (retValue);  
  62.     }  
  63.   
  64.     private byte[] intToDWord(int parValue) {  
  65.   
  66.         byte retValue[] = new byte[4];  
  67.   
  68.         retValue[0] = (byte) (parValue & 0x00FF);  
  69.         retValue[1] = (byte) ((parValue >> 8) & 0x000000FF);  
  70.         retValue[2] = (byte) ((parValue >> 16) & 0x000000FF);  
  71.         retValue[3] = (byte) ((parValue >> 24) & 0x000000FF);  
  72.   
  73.         return (retValue);  
  74.   
  75.     }  
  76.       
  77.     private void writeBitmapFileHeader () {  
  78.           
  79.         bmpBuffer.put(bfType);  
  80.         bmpBuffer.put(intToDWord (bfSize));  
  81.         bmpBuffer.put(intToWord (bfReserved1));  
  82.         bmpBuffer.put(intToWord (bfReserved2));  
  83.         bmpBuffer.put(intToDWord (bfOffBits));  
  84.           
  85.     }  
  86.       
  87.     private void writeBitmapInfoHeader () {  
  88.           
  89.         bmpBuffer.put(intToDWord (biSize));      
  90.         bmpBuffer.put(intToDWord (biWidth));      
  91.         bmpBuffer.put(intToDWord (biHeight));      
  92.         bmpBuffer.put(intToWord (biPlanes));      
  93.         bmpBuffer.put(intToWord (biBitCount));      
  94.         bmpBuffer.put(intToDWord (biCompression));      
  95.         bmpBuffer.put(intToDWord (biSizeImage));      
  96.         bmpBuffer.put(intToDWord (biXPelsPerMeter));      
  97.         bmpBuffer.put(intToDWord (biYPelsPerMeter));      
  98.         bmpBuffer.put(intToDWord (biClrUsed));      
  99.         bmpBuffer.put(intToDWord (biClrImportant));   
  100.           
  101.     }  
  102. }  


         测试程序完整工程在此暂不提供。

5.5集成测试

        集成测试有两点需要注意,在运行程序前,需要把动态库复制到模拟器的/system/lib目录下面,还需要把需要解码的视频传到模拟器的/tmp目录下。
       这里要明确的是,OPhone和Symbian的模拟器都做的太不人性化了,Symbian复制一个文件到模拟器中,要进一堆很深的目录,OPhone的 更恼火,需要敲命令把文件传递到模拟器里,说实话,仅在这点上,Mobile的模拟器做的还是非常人性化的。
       命令:

  1. PATH=D:"OPhone"OPhone SDK"tools"  
  2. adb.exe remount  
  3. adb.exe push D:"Eclipse"workspace"H264Example"libs"armeabi"libH264Decode.so /system/lib  
  4. adb.exe push D:"Eclipse"workspace"H264Example"Demo.264 /tmp  
  5. pause  


      这里解释一下abd push命令:
      adb push <本地文件路径> <远程文件路径>    - 复制文件或者目录到模拟器
      在Eclipse中,启动库测试程序,得到画面如下:
 

        FAQ 3:

        模拟器黑屏怎么办?
        这可能是由于模拟器启动速度比较慢所引起的,所以需要多等一会。希望下个版本能够改进。

原文地址:http://www.ophonesdn.com/article/show/45;jsessionid=306BD3BE92F43DC693BEB09B0234B036



国内最棒的Google Android技术社区(eoeandroid),欢迎访问!

《银河系列原创教程》发布

《Java Web开发速学宝典》出版,欢迎定购

相关实践学习
阿里云百炼xAnalyticDB PostgreSQL构建AIGC应用
通过该实验体验在阿里云百炼中构建企业专属知识库构建及应用全流程。同时体验使用ADB-PG向量检索引擎提供专属安全存储,保障企业数据隐私安全。
AnalyticDB PostgreSQL 企业智能数据中台:一站式管理数据服务资产
企业在数据仓库之上可构建丰富的数据服务用以支持数据应用及业务场景;ADB PG推出全新企业智能数据平台,用以帮助用户一站式的管理企业数据服务资产,包括创建, 管理,探索, 监控等; 助力企业在现有平台之上快速构建起数据服务资产体系
目录
相关文章
|
7月前
|
Web App开发 编解码 安全
视频会议技术 入门探究:WebRTC、Qt与FFmpeg在视频编解码中的应用
视频会议技术 入门探究:WebRTC、Qt与FFmpeg在视频编解码中的应用
683 4
|
7月前
|
编解码 Linux 5G
FFmpeg开发笔记(二十)Linux环境给FFmpeg集成AVS3解码器
AVS3,中国制定的第三代音视频标准,是首个针对8K和5G的视频编码标准,相比AVS2和HEVC性能提升约30%。uavs3d是AVS3的解码器,支持8K/60P实时解码,且在各平台有优秀表现。要为FFmpeg集成AVS3解码器libuavs3d,需从GitHub下载最新源码,解压后配置、编译和安装。之后,重新配置FFmpeg,启用libuavs3d并编译安装,通过`ffmpeg -version`确认成功集成。
134 0
FFmpeg开发笔记(二十)Linux环境给FFmpeg集成AVS3解码器
|
编解码 API 开发者
HarmonyOS学习路之开发篇—多媒体开发(音频开发 二)
音频采集的主要工作是通过输入设备将声音采集并转码为音频数据,同时对采集任务进行管理。
|
编解码 算法 内存技术
HarmonyOS学习路之开发篇—多媒体开发(音频开发 一)
HarmonyOS音频模块支持音频业务的开发,提供音频相关的功能,主要包括音频播放、音频采集、音量管理和短音播放等。
|
存储 文件存储
HarmonyOS学习路之开发篇—多媒体开发(视频开发 二)
视频播放开发 场景介绍 视频播放包括播放控制、播放设置和播放查询,如播放的开始/停止、播放速度设置和是否循环播放等。
|
编解码 开发者
HarmonyOS学习路之开发篇—多媒体开发(视频开发 一)
HarmonyOS视频模块支持视频业务的开发和生态开放,开发者可以通过已开放的接口很容易地实现视频媒体的播放、操作和新功能开发。视频媒体的常见操作有视频编解码、视频合成、视频提取、视频播放以及视频录制等。
|
开发框架 .NET 数据处理
海思3559万能平台搭建:RTSP优化buffpool的引入
海思3559万能平台搭建:RTSP优化buffpool的引入
470 0
海思3559万能平台搭建:RTSP优化buffpool的引入
|
Android开发 C++
嵌入式实践教程--Android音频开发日志(一)—移植FFmpeg
嵌入式实践教程--Android音频开发日志(一)—移植FFmpeg
嵌入式实践教程--Android音频开发日志(一)—移植FFmpeg
|
Android开发 内存技术
嵌入式实践教程--Android音视频开发(二)-OpenSLES播放PCM数据
嵌入式实践教程--Android音视频开发(二)-OpenSLES播放PCM数据