小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

FFMpeg壓縮Android攝像頭數(shù)據(jù)寫成H264格式文件

 mediatv 2016-07-23


Android端獲取攝像頭數(shù)據(jù)有好幾種。我使用的是onPreviewFrame(byte data[],Camera camera);這個回調(diào)函數(shù)

遇到的問題:

問題1、打印了下data[]的長度,是3110400。

手機攝像頭像素是1920*1080=2073600

3110400/2073600=1.5,這個1.5就懂了。

data[]里默認存放的是YUV420SP格式的幀,有YUV三個分量。其中像素占2/3,就是Y分量,是控制整體的視頻內(nèi)容的。而U、V占剩下的1/3,是控制顏色的。所以1920*1080=2073600算出來的是Y分量。剩下的是U和V的分量。幀的width和height就是Y分量的width和height。

問題2、YUV格式有好幾種,有YUV420SP有YUV420P,等等,只看這兩種吧。


這兩張圖里也能看出來,Y分量通常占整個幀長度的2/3。

第一張YUV420SP,下邊U和V是相互交錯著的,而YUV420P的U和V就很整齊。YUV420P這個性質很重要,我們要利用這個性質,使分離YUV分量變得容易。


問題3、改變onPreviewFrame()回調(diào)的data[]的大小,改變預覽幀data[]的格式。

直接上

  1. <span style="white-space:pre">    </span>Camera.Parameters parameters = mCamera.getParameters();  
通過parameters來設置預覽幀的大?。ň褪歉淖儙南袼兀?,和預覽幀的格式。

  1. parameters.setPreviewSize(864480);  
  2. parameters.setPreviewFormat(ImageFormat.YV12);  

如果你不設置setPreviewFormat的話,默認回調(diào)的data[]格式是YUV420SP。CbCr就是U和V。Cb控制藍色,Cr控制紅色。直接點進源碼里看就好。

所以一定要設置一下格式為ImageFormat.YV12,就是YUV420P。ImageFormat.YV12這個是我在prameters.setPreviewFormat(),下圖里找到的。。。

最后,最重要一點:把parameters設置回去!我忘了設置,調(diào)了好久,發(fā)現(xiàn)data[]永遠是3110400大小,改了prameters.setPreviewFormat()也沒用。

  1. mCamera.setParameters(parameters);  

Android端完了,剩下的就是底層NDK端FFMpeg的調(diào)試。

講講遇到的問題:

問題1、由于開始先VS上做的實驗,然后移植。結果導致把所有代碼都放到一個jni函數(shù)里,結果一直崩潰,原來是:因為每一幀都要傳進來壓縮,所以一直在執(zhí)行av_register_all();等等類似代碼。導致崩潰。所以要把這類初始化的過程,單獨放到一個native方法里。把AVCodecContext *pCodecCtx;這種聲明成全局變量。

問題2、把傳進來的jbyteArray轉換成jbyte *,忘了在結束的時候釋放掉,導致運行一秒鐘左右就會內(nèi)存溢出。

  1. <span style="font-size:18px;">jbyte *yuv420sp = (jbyte*) (*env)->GetByteArrayElements(env, yuvdata, 0);</span>  
最后一定要有這句,來把內(nèi)存釋放掉
  1. <span style="font-size:18px;">(*env)->ReleaseByteArrayElements(env, yuvdata, yuv420sp, 0);</span>  

問題3、在jni里寫本地文件,路徑為char filename_out[] = "/storage/emulated/0/yourname.h264";

JAVA

  1. public class MainActivity extends Activity implements Camera.PreviewCallback,  
  2.         SurfaceHolder.Callback {  
  3.     List<Size> list;  
  4.     SurfaceView mSurfaceView;  
  5.     SurfaceHolder mSurfaceHolder;  
  6.     Camera mCamera;  
  7.     TextView tv;  
  8.     Handler mHandler = new Handler() {  
  9.         public void handleMessage(android.os.Message msg) {  
  10.             switch (msg.what) {  
  11.             case 1:  
  12.                 byte[] bytedata = msg.getData().getByteArray("messageyuvdata");  
  13.                 if (bytedata != null) {  
  14.                     // tv.setText(temp+"");  
  15.                     int count = addVideoData(bytedata);  
  16.                     tv.setText("length:"+length);  
  17.                 }  
  18.                 break;  
  19.             case 2 :  
  20.                 String s = msg.getData().getString("supportFrameSize");  
  21.                 tv.setText(s);  
  22.                 break;  
  23.             }  
  24.         };  
  25.     };  
  26.   
  27.     int temp = 0;  
  28.     int length = 0;  
  29.     @Override  
  30.     protected void onCreate(Bundle savedInstanceState) {  
  31.         // TODO Auto-generated method stub  
  32.         super.onCreate(savedInstanceState);  
  33.         setContentView(R.layout.activity_main);  
  34.         tv = (TextView) findViewById(R.id.tv);  
  35.         temp = FFMpegLib.getVersion();  
  36.         mSurfaceView = (SurfaceView) this.findViewById(R.id.surfaceview);  
  37.         mSurfaceHolder = mSurfaceView.getHolder();  
  38.         mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);  
  39.         mSurfaceHolder.addCallback(this);  
  40.   
  41.     }  
  42.   
  43.     @Override  
  44.     public void onPreviewFrame(byte[] data, Camera camera) {  
  45.         length = data.length;  
  46.         Log.i("log", data + "");  
  47.         Message msg = new Message();  
  48.         Bundle bl = new Bundle();  
  49.         bl.putByteArray("messageyuvdata", data);  
  50.         msg.setData(bl);  
  51.         msg.what = 1;  
  52.         mHandler.sendMessage(msg);  
  53.     }  
  54.   
  55.     @Override  
  56.     public void surfaceChanged(SurfaceHolder holder, int format, int width,  
  57.             int height) {  
  58.         // TODO Auto-generated method stub  
  59.         mCamera.startPreview();  
  60.     }  
  61.   
  62.     @Override  
  63.     public void surfaceCreated(SurfaceHolder holder) {  
  64.         // TODO Auto-generated method stub  
  65.         // 打開前置攝像頭  
  66.         mCamera = Camera.open(CameraInfo.CAMERA_FACING_BACK);  
  67.   
  68.         try {  
  69.             Camera.Parameters parameters = mCamera.getParameters();  
  70.             List<Integer> supportedPictureFormats = parameters  
  71.                     .getSupportedPictureFormats();  
  72.             for (Integer integer : supportedPictureFormats) {  
  73.                 Log.i("sun", integer + "");  
  74.             }  
  75.             list = parameters.getSupportedPreviewSizes();  
  76.             parameters.setPreviewSize(864480);  
  77.             parameters.setPreviewFormat(ImageFormat.YV12);  
  78.             parameters.setPreviewFpsRange(2020); // 每秒顯示20~30幀  
  79.             parameters.setPictureFormat(PixelFormat.JPEG); // 設置圖片格式  
  80.             //parameters.setPreviewFormat(PixelFormat.YCbCr_420_SP);  
  81.             //parameters.setFlashMode(Parameters.FLASH_MODE_TORCH);  
  82.               
  83.             String supportFrameSize = null;  
  84.             for (int i = 0; i < list.size(); i++) {  
  85.                 int width =list.get(i).width;  
  86.                 int height =list.get(i).height;  
  87.                 supportFrameSize = supportFrameSize+width+"-"+height+"||||||";  
  88.             }  
  89.               
  90.               
  91.             Message msg = new Message();  
  92.             Bundle bl = new Bundle();  
  93.             bl.putString("supportFrameSize", supportFrameSize);  
  94.             msg.setData(bl);  
  95.             msg.what = 2;  
  96.             mHandler.sendMessage(msg);  
  97.             mCamera.setParameters(parameters);  
  98.               
  99.         } catch (Exception e) {  
  100.             e.printStackTrace();  
  101.         }  
  102.           
  103.         // 開始預覽  
  104.         try {  
  105.             // 設置哪個surfaceView顯示圖片  
  106.             mCamera.setPreviewDisplay(mSurfaceHolder);  
  107.         } catch (IOException e) {  
  108.             e.printStackTrace();  
  109.         }  
  110.           
  111.         // 設置預覽幀的接口,就是通過這個接口,我們來獲得預覽幀的數(shù)據(jù)的  
  112.           
  113.         mCamera.setPreviewCallback(MainActivity.this);  
  114.         mCamera.startPreview();  
  115.     }  
  116.   
  117.     @Override  
  118.     public void surfaceDestroyed(SurfaceHolder holder) {  
  119.         // TODO Auto-generated method stub  
  120.         mCamera.stopPreview();  
  121.         mCamera.release();  
  122.     }  
  123.   
  124.     public synchronized int addVideoData(byte[] data) {  
  125.         int s = FFMpegLib.Encoding(data);  
  126.         return s;  
  127.     }  
  128.   
  129.     @Override  
  130.     protected void onStart() {  
  131.         super.onStart();  
  132.     }  
  133.     @Override  
  134.     protected void onDestroy() {  
  135.         super.onDestroy();  
  136.         FFMpegLib.CloseVideo();  
  137.     }  
  138. }  



JNI

  1. #include <string.h>  
  2. #include <stdio.h>  
  3. #include <android/log.h>  
  4. #include <stdlib.h>  
  5. #include <jni.h>  
  6. #include <ffmpeg/libavcodec/avcodec.h>  
  7. #include "ffmpeg/libavformat/avformat.h"  
  8. #include "ffmpeg/libavdevice/avdevice.h"  
  9. #include "ffmpeg/libavutil/avutil.h"  
  10. #include "ffmpeg/libavutil/opt.h"  
  11. #include "ffmpeg/libavutil/imgutils.h"  
  12. #include "ffmpeg/libavutil/log.h"  
  13.   
  14. #define TEST_H264  1  
  15.   
  16. #ifdef ANDROID  
  17. #include <jni.h>  
  18. #include <android/log.h>  
  19. #define LOGE(format, ...)  __android_log_print(ANDROID_LOG_ERROR, "(>_<)", format, ##__VA_ARGS__)  
  20. #define LOGI(format, ...)  __android_log_print(ANDROID_LOG_INFO,  "(^_^)", format, ##__VA_ARGS__)  
  21. #else  
  22. #define LOGE(format, ...)  printf("(>_<) " format "\n", ##__VA_ARGS__)  
  23. #define LOGI(format, ...)  printf("(^_^) " format "\n", ##__VA_ARGS__)  
  24. #endif  
  25.   
  26. AVCodec *pCodec;  
  27. AVCodecContext *pCodecCtx = NULL;  
  28. int i, ret, got_output;  
  29. FILE *fp_out;  
  30. AVFrame *pFrame;  
  31. AVPacket pkt;  
  32. int y_size;  
  33. int framecnt = 0;  
  34. char filename_out[] = "/storage/emulated/0/yourname.h264";  
  35. int in_w = 864, in_h = 480;  
  36. int count = 0;  
  37.   
  38. JNIEXPORT jint JNICALL Java_com_cpi_ffmpeg_FFMpegLib_getVersion(JNIEnv *env,  
  39.         jclass jclass) {  
  40.     avcodec_register_all();  
  41.   
  42.     pCodec = avcodec_find_encoder(AV_CODEC_ID_H264);  
  43.     if (!pCodec) {  
  44.         printf("Codec not found\n");  
  45.         return -1;  
  46.     }  
  47.     pCodecCtx = avcodec_alloc_context3(pCodec);  
  48.     if (!pCodecCtx) {  
  49.         printf("Could not allocate video codec context\n");  
  50.         return -1;  
  51.     }  
  52.     pCodecCtx->bit_rate = 400000;  
  53.     pCodecCtx->width = in_w;  
  54.     pCodecCtx->height = in_h;  
  55.     pCodecCtx->time_base.num = 1;  
  56.     pCodecCtx->time_base.den = 20;  
  57.     pCodecCtx->gop_size = 10;  
  58.     pCodecCtx->max_b_frames = 5;  
  59.     pCodecCtx->pix_fmt = AV_PIX_FMT_YUV420P;  
  60.   
  61.     av_opt_set(pCodecCtx->priv_data, "preset""superfast", 0);  
  62. //  av_opt_set(pCodecCtx->priv_data, "preset", "slow", 0);  
  63.     av_opt_set(pCodecCtx->priv_data, "tune""zerolatency", 0);  
  64.   
  65.   
  66.   
  67.     if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0) {  
  68.         printf("Could not open codec\n");  
  69.         return -1;  
  70.     }  
  71.     if ((fp_out = fopen(filename_out, "wb")) == NULL) {  
  72.         return -1;  
  73.     }  
  74.     y_size = pCodecCtx->width * pCodecCtx->height;  
  75.   
  76.     return 1;  
  77. }  
  78. JNIEXPORT jint JNICALL Java_com_cpi_ffmpeg_FFMpegLib_Encoding(JNIEnv *env,  
  79.         jclass jclass, jbyteArray yuvdata) {  
  80.   
  81.     jbyte *yuv420sp = (jbyte*) (*env)->GetByteArrayElements(env, yuvdata, 0);  
  82.   
  83. //  av_opt_set(pCodecCtx->priv_data, "preset", "superfast", 0);  
  84. //  av_opt_set(pCodecCtx->priv_data, "tune", "zerolatency", 0);  
  85.   
  86.   
  87.     pFrame = av_frame_alloc();  
  88.     if (!pFrame) {  
  89.         printf("Could not allocate video frame\n");  
  90.         return -1;  
  91.     }  
  92.     pFrame->format = pCodecCtx->pix_fmt;  
  93.     pFrame->width = pCodecCtx->width;  
  94.     pFrame->height = pCodecCtx->height;  
  95.   
  96.     ret = av_image_alloc(pFrame->data, pFrame->linesize, pCodecCtx->width,  
  97.             pCodecCtx->height, pCodecCtx->pix_fmt, 16);  
  98.     if (ret < 0) {  
  99.         printf("Could not allocate raw picture buffer\n");  
  100.         return -1;  
  101.     }  
  102.   
  103.     av_init_packet(&pkt);  
  104.     pkt.data = NULL; // packet data will be allocated by the encoder  
  105.     pkt.size = 0;  
  106.   
  107.     //Read raw YUV data  這里出錯了,是按YUV_SP處理的 應該是YUV_P  
  108.     pFrame->data[0] = yuv420sp; //PCM Data  
  109.     pFrame->data[1] = yuv420sp + y_size * 5 / 4; // V  
  110.     pFrame->data[2] = yuv420sp + y_size; // U  
  111.     pFrame->pts = count;  
  112.     count++;  
  113.     /* encode the image */  
  114.     ret = avcodec_encode_video2(pCodecCtx, &pkt, pFrame, &got_output);  
  115.     int sizee = pkt.size;  
  116.     if (ret < 0) {  
  117.         printf("Error encoding frame\n");  
  118.         return -1;  
  119.     }  
  120.     if (got_output) {  
  121.         printf("Succeed to encode frame: %5d\tsize:%5d\n", framecnt, pkt.size);  
  122.         framecnt++;  
  123.         fwrite(pkt.data, 1, pkt.size, fp_out);  
  124.         av_free_packet(&pkt);  
  125.         av_freep(&pFrame->data[0]);  
  126.         av_frame_free(&pFrame);  
  127.         //(*env)->ReleaseByteArrayElements(env, yuvdata, ydata, 0);  
  128.         // return framecnt;  
  129.     }  
  130.     //av_freep(&pFrame->data[0]);  
  131.     //av_frame_free(&pFrame);  
  132.     (*env)->ReleaseByteArrayElements(env, yuvdata, yuv420sp, 0);  
  133.     return 1;  
  134. }  
  135.   
  136. JNIEXPORT jint JNICALL Java_com_cpi_ffmpeg_FFMpegLib_CloseVideo(JNIEnv *env,  
  137.         jclass jclass) {  
  138.   
  139.     for (got_output = 1; got_output; i++) {  
  140.         ret = avcodec_encode_video2(pCodecCtx, &pkt, NULL, &got_output);  
  141.         if (ret < 0) {  
  142.             printf("Error encoding frame\n");  
  143.             return -1;  
  144.         }  
  145.         if (got_output) {  
  146.             printf("Flush Encoder: Succeed to encode 1 frame!\tsize:%5d\n",  
  147.                     pkt.size);  
  148.             fwrite(pkt.data, 1, pkt.size, fp_out);  
  149.             av_free_packet(&pkt);  
  150.         }  
  151.     }  
  152.   
  153.     fclose(fp_out);  
  154.     avcodec_close(pCodecCtx);  
  155.     av_free(pCodecCtx);  
  156.     av_freep(&pFrame->data[0]);  
  157.     av_frame_free(&pFrame);  
  158.     return 0;  
  159. }  

    本站是提供個人知識管理的網(wǎng)絡存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權內(nèi)容,請點擊一鍵舉報。
    轉藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多