2011-12-15 147 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