2011-12-15 145 views
3

注:由於最初提出的問題反映了一些什麼,我已經瞭解裝載現場攝像機圖像到FFmpeg的圖書館我已經更新了這一點。對視頻進行編碼會導致本地代碼崩潰

我使用ffmpegjavacv編譯爲Android爲我的應用程序編碼/解碼視頻。 (請注意,原來,我試圖用ffmpeg-java,但它有一些不兼容的庫)

原來的問題:,我碰到的問題是,我目前得到每幀爲Bitmap(只是一個簡單android.graphics.Bitmap),我不知道如何將它塞入編碼器。

解決方案在javacvffmpeg:)使用avpicture_fill(從Android的格式是所謂YUV420P,雖然我無法驗證這一點,直到我的編碼器問題(下)是固定的。

avcodec.avpicture_fill((AVPicture)mFrame, picPointer, avutil.PIX_FMT_YUV420P, VIDEO_WIDTH, VIDEO_HEIGHT) 

現在的問題:是應該實際編碼數據線崩潰的線程。我得到了一個我無法理解的大型本地代碼堆棧跟蹤。有人有建議嗎?

這裏是我使用的實例所有ffmpeg庫代碼:

avcodec.avcodec_register_all(); 
    avcodec.avcodec_init(); 
    avformat.av_register_all(); 

    mCodec = avcodec.avcodec_find_encoder(avcodec.CODEC_ID_H263); 
    if (mCodec == null) 
    { 
     Logging.Log("Unable to find encoder."); 
     return; 
    } 
    Logging.Log("Found encoder."); 

    mCodecCtx = avcodec.avcodec_alloc_context(); 
    mCodecCtx.bit_rate(300000); 
    mCodecCtx.codec(mCodec); 
    mCodecCtx.width(VIDEO_WIDTH); 
    mCodecCtx.height(VIDEO_HEIGHT); 
    mCodecCtx.pix_fmt(avutil.PIX_FMT_YUV420P); 
    mCodecCtx.codec_id(avcodec.CODEC_ID_H263); 
    mCodecCtx.codec_type(avutil.AVMEDIA_TYPE_VIDEO); 
    AVRational ratio = new AVRational(); 
    ratio.num(1); 
    ratio.den(30); 
    mCodecCtx.time_base(ratio); 
    mCodecCtx.coder_type(1); 
    mCodecCtx.flags(mCodecCtx.flags() | avcodec.CODEC_FLAG_LOOP_FILTER); 
    mCodecCtx.me_cmp(avcodec.FF_LOSS_CHROMA); 
    mCodecCtx.me_method(avcodec.ME_HEX); 
    mCodecCtx.me_subpel_quality(6); 
    mCodecCtx.me_range(16); 
    mCodecCtx.gop_size(30); 
    mCodecCtx.keyint_min(10); 
    mCodecCtx.scenechange_threshold(40); 
    mCodecCtx.i_quant_factor((float) 0.71); 
    mCodecCtx.b_frame_strategy(1); 
    mCodecCtx.qcompress((float) 0.6); 
    mCodecCtx.qmin(10); 
    mCodecCtx.qmax(51); 
    mCodecCtx.max_qdiff(4); 
    mCodecCtx.max_b_frames(1); 
    mCodecCtx.refs(2); 
    mCodecCtx.directpred(3); 
    mCodecCtx.trellis(1); 
    mCodecCtx.flags2(mCodecCtx.flags2() | avcodec.CODEC_FLAG2_BPYRAMID | avcodec.CODEC_FLAG2_WPRED | avcodec.CODEC_FLAG2_8X8DCT | avcodec.CODEC_FLAG2_FASTPSKIP); 

    if (avcodec.avcodec_open(mCodecCtx, mCodec) == 0) 
    { 
     Logging.Log("Unable to open encoder."); 
     return; 
    } 
    Logging.Log("Encoder opened."); 

    mFrameSize = avcodec.avpicture_get_size(avutil.PIX_FMT_YUV420P, VIDEO_WIDTH, VIDEO_HEIGHT); 
    Logging.Log("Frame size - '" + mFrameSize + "'."); 
    //mPic = new AVPicture(mPicSize); 
    mFrame = avcodec.avcodec_alloc_frame(); 
    if (mFrame == null) 
    { 
     Logging.Log("Unable to alloc frame."); 
    } 

這就是我希望能夠接下來要執行:

BytePointer picPointer = new BytePointer(data); 
    int bBuffSize = mFrameSize; 

    BytePointer bBuffer = new BytePointer(bBuffSize); 

    int picSize = 0; 
    if ((picSize = avcodec.avpicture_fill((AVPicture)mFrame, picPointer, avutil.PIX_FMT_YUV420P, VIDEO_WIDTH, VIDEO_HEIGHT)) <= 0) 
    { 
     Logging.Log("Couldn't convert preview to AVPicture (" + picSize + ")"); 
     return; 
    } 
    Logging.Log("Converted preview to AVPicture (" + picSize + ")"); 

    VCAP_Package vPackage = new VCAP_Package(); 

    if (mCodecCtx.isNull()) 
    { 
     Logging.Log("Codec Context is null!"); 
    } 

    //encode the image 
    int size = avcodec.avcodec_encode_video(mCodecCtx, bBuffer, bBuffSize, mFrame); 

    int totalSize = 0; 
    while (size >= 0) 
    { 
     totalSize += size; 
     Logging.Log("Encoded '" + size + "' bytes."); 
     //Get any delayed frames 
     size = avcodec.avcodec_encode_video(mCodecCtx, bBuffer, bBuffSize, null); 
    } 
    Logging.Log("Finished encoding. (" + totalSize + ")"); 

但是,截至目前,我不知道如何將Bitmap放入正確的位置,或者如果我正確設置了該設置。

關於代碼的幾點注意事項: - VIDEO_WIDTH = 352 - VIDEO_HEIGHT = 288 - VIDEO_FPS = 30;

+0

發現如果成功地獲得視頻,請您與我們分享一個鏈接到一個miniproject? – Lunatikul 2013-03-27 16:01:34

回答

3

很多搜​​索的東西之後,我想通了,你必須加載指針在一個相當嚴格和尷尬的方式。這是我得到的一切工作:

編解碼器設置:

avcodec.avcodec_register_all(); 
    avcodec.avcodec_init(); 
    avformat.av_register_all(); 

    /* find the H263 video encoder */ 
    mCodec = avcodec.avcodec_find_encoder(avcodec.CODEC_ID_H263); 
    if (mCodec == null) { 
     Log.d("TEST_VIDEO", "avcodec_find_encoder() run fail."); 
    } 

    mCodecCtx = avcodec.avcodec_alloc_context(); 
    picture = avcodec.avcodec_alloc_frame(); 

    /* put sample parameters */ 
    mCodecCtx.bit_rate(400000); 
    /* resolution must be a multiple of two */ 
    mCodecCtx.width(VIDEO_WIDTH); 
    mCodecCtx.height(VIDEO_HEIGHT); 
    /* frames per second */ 
    AVRational avFPS = new AVRational(); 
    avFPS.num(1); 
    avFPS.den(VIDEO_FPS); 
    mCodecCtx.time_base(avFPS); 
    mCodecCtx.pix_fmt(avutil.PIX_FMT_YUV420P); 
    mCodecCtx.codec_id(avcodec.CODEC_ID_H263); 
    mCodecCtx.codec_type(avutil.AVMEDIA_TYPE_VIDEO); 

    /* open it */ 
    if (avcodec.avcodec_open(mCodecCtx, mCodec) < 0) { 
     Log.d("TEST_VIDEO", "avcodec_open() run fail."); 
    } 

    /* alloc image and output buffer */ 
    output_buffer_size = 100000; 
    output_buffer = avutil.av_malloc(output_buffer_size); 

    size = mCodecCtx.width() * mCodecCtx.height(); 
    picture_buffer = avutil.av_malloc((size * 3)/2); /* size for YUV 420 */ 

    picture.data(0, new BytePointer(picture_buffer)); 
    picture.data(1, picture.data(0).position(size)); 
    picture.data(2, picture.data(1).position(size/4)); 
    picture.linesize(0, mCodecCtx.width()); 
    picture.linesize(1, mCodecCtx.width()/2); 
    picture.linesize(2, mCodecCtx.width()/2); 

處理預覽數據:

//(1)Convert byte[] first 
    byte[] data420 = new byte[data.length]; 
    convert_yuv422_to_yuv420(data, data420, VIDEO_WIDTH, VIDEO_HEIGHT); 

    //(2) Fill picture buffer 
    int data1_offset = VIDEO_HEIGHT * VIDEO_WIDTH; 
    int data2_offset = data1_offset * 5/4; 
    int pic_linesize_0 = picture.linesize(0); 
    int pic_linesize_1 = picture.linesize(1); 
    int pic_linesize_2 = picture.linesize(2); 

    //Y 
    for(y = 0; y < VIDEO_HEIGHT; y++) 
    { 
     for(x = 0; x < VIDEO_WIDTH; x++) 
     { 
      picture.data(0).put((y * pic_linesize_0 + x), data420[y * VIDEO_WIDTH + x]); 
     } 
    } 

    //Cb and Cr 
    for(y = 0; y < VIDEO_HEIGHT/2; y++) { 
     for(x = 0; x < VIDEO_WIDTH/2; x++) { 
      picture.data(1).put((y * pic_linesize_1 + x), data420[data1_offset + y * VIDEO_WIDTH/2 + x]); 
      picture.data(2).put((y * pic_linesize_2 + x), data420[data2_offset + y * VIDEO_WIDTH/2 + x]); 
     } 
    } 

    //(2)Encode 
    //Encode the image into output_buffer 
    out_size = avcodec.avcodec_encode_video(mCodecCtx, new BytePointer(output_buffer), output_buffer_size, picture); 
    Log.d("TEST_VIDEO", "Encoded '" + out_size + "' bytes"); 

    //Delayed frames 
    for(; out_size > 0; i++) { 
     out_size = avcodec.avcodec_encode_video(mCodecCtx, new BytePointer(output_buffer), output_buffer_size, null); 
     Log.d("TEST_VIDEO", "Encoded '" + out_size + "' bytes"); 
     //fwrite(output_buffer, 1, out_size, file); 
    } 

我仍在努力將數據打包,但正在進行的測試項目可這裏@http://code.google.com/p/test-video-encode/

0

是否安卓圖形庫支持YUV格式:

codecCtx.pix_fmt = AVCodecLibrary.PIX_FMT_YUV420P; 

看看你是否可以將其設置爲ARGB或RGB32。我知道android圖形庫支持這種像素格式。

PS:我不知道的FFmpeg

+0

對於我的項目,我需要編碼的視頻輸出YUV420P,但如果有必要,我可以進行轉換。我只是不明白我應該加載ffmpeg來處理它的數據。 – gtcompscientist 2011-12-15 13:37:52