Convert raw yuv to mp4 crashed on android

705 Views Asked by At

Here is my steps:

  1. Decode a jpeg file to rgb565;(Success);

  2. Convert rgb565 to yuv420;(Not sure if it works, function "Bitmap2Yuv420")

  3. Convert yuv420 to mp4. (Crash when call avcodec_open2);

And that is the codes:

void ADKJpegDecoder::Bitmap2Yuv420(const char * outfilename) {
unsigned char *destination = new unsigned char[m_Width * m_Height
        * m_BytesPerPixel / 2];
unsigned char* rgb = m_RawImage;
size_t image_size = m_Width * m_Height;
size_t upos = image_size;
size_t vpos = upos + upos / 4;
size_t i = 0;

for (size_t line = 0; line < m_Height; ++line) {
    if (!(line % 2)) {
        for (size_t x = 0; x < m_Width; x += 2) {
            char r = rgb[3 * i];
            char g = rgb[3 * i + 1];
            char b = rgb[3 * i + 2];

            destination[i++] = ((66 * r + 129 * g + 25 * b) >> 8) + 16;

            destination[upos++] = ((-38 * r + -74 * g + 112 * b) >> 8)
                    + 128;
            destination[vpos++] = ((112 * r + -94 * g + -18 * b) >> 8)
                    + 128;

            r = rgb[3 * i];
            g = rgb[3 * i + 1];
            b = rgb[3 * i + 2];

            destination[i++] = ((66 * r + 129 * g + 25 * b) >> 8) + 16;
        }
    } else {
        for (size_t x = 0; x < m_Width; x += 1) {
            char r = rgb[3 * i];
            char g = rgb[3 * i + 1];
            char b = rgb[3 * i + 2];

            destination[i++] = ((66 * r + 129 * g + 25 * b) >> 8) + 16;
        }
    }
}

ADKVideoEncoder::getInstance()->startEncodeVideo(destination);
delete[] destination;

}

void ADKVideoEncoder::startEncodeVideo(unsigned char* rawDatas) {
AVFormatContext* oc;
AVOutputFormat* fmt;
AVStream* video_st;
AVCodecContext* c;

double video_pts;
uint8_t* video_outbuf;
AVFrame* picture;
int size;
int ret;
int video_outbuf_size;

const char* filename = "/sdcard/test.mpg";

av_register_all();

fmt = av_guess_format(NULL, filename, NULL);
oc = avformat_alloc_context();
oc->oformat = fmt;
snprintf(oc->filename, sizeof(oc->filename), "%s", filename);

video_st = NULL;
if (fmt->video_codec != CODEC_ID_NONE) {
    video_st = av_new_stream(oc, 0);
    c = video_st->codec;
    c->codec_id = fmt->video_codec;
    c->codec_type = AVMEDIA_TYPE_VIDEO;
    c->bit_rate = 400000;
    c->width = 320;
    c->height = 480;
    c->time_base.num = 1;
    c->time_base.den = 1;
    c->gop_size = 12;
    c->pix_fmt = PIX_FMT_YUV420P;
    c->max_b_frames = 0;
    if (!strcmp(oc->oformat->name, "mp4")
            || !strcmp(oc->oformat->name, "mov")
            || !strcmp(oc->oformat->name, "3gp")) {
        c->flags |= CODEC_FLAG_GLOBAL_HEADER;
    }
}

av_dump_format(oc, 0, filename, 1);
if (video_st) {
    AVCodec* codec = avcodec_find_encoder(c->codec_id);
    if (!codec) {
        return;
    }
    AVDictionary *optionsDict = NULL;
    if (avcodec_open2(c, codec, &optionsDict) < 0) {
        return;
    }
    if (!(oc->oformat->flags & AVFMT_RAWPICTURE)) {
        video_outbuf_size = 20000;
        video_outbuf = (uint8_t*) av_malloc(video_outbuf_size);
    }
    picture = avcodec_alloc_frame();
    size = avpicture_get_size(c->pix_fmt, c->width, c->height);
    avpicture_fill((AVPicture*) picture, rawDatas, c->pix_fmt, c->width,
            c->height);
}

if (!(fmt->flags & AVFMT_NOFILE)) {
    if (avio_open(&oc->pb, filename, AVIO_FLAG_WRITE) < 0) {
        return;
    }
}
avformat_write_header(oc, 0);

if (video_st) {
    video_pts = (double) (video_st->pts.val * video_st->time_base.num
            / video_st->time_base.den);
} else {
    video_pts = 0.0;
}
if (!video_st/* || video_pts >= 5.0*/) {
    return;
}
c = video_st->codec;
size = c->width * c->height;

picture->data[0] = rawDatas;
picture->data[1] = rawDatas + size;
picture->data[2] = rawDatas + size * 5 / 4;

if (oc->oformat->flags & AVFMT_RAWPICTURE) {
    AVPacket pkt;
    av_init_packet(&pkt);
    pkt.flags |= AV_PKT_FLAG_KEY;
    pkt.stream_index = video_st->index;
    pkt.data = (uint8_t*) picture;
    pkt.size = sizeof(AVPicture);
    ret = av_write_frame(oc, &pkt);
} else {
    int out_size = avcodec_encode_video(c, video_outbuf, video_outbuf_size,
            picture);
    if (out_size > 0) {
        AVPacket pkt;
        av_init_packet(&pkt);
        pkt.pts = av_rescale_q(c->coded_frame->pts, c->time_base,
                video_st->time_base);
        if (c->coded_frame->key_frame) {
            pkt.flags |= AV_PKT_FLAG_KEY;
        }
        pkt.stream_index = video_st->index;
        pkt.data = video_outbuf;
        pkt.size = out_size;
        ret = av_write_frame(oc, &pkt);
    }
}

if (video_st) {
    avcodec_close(video_st->codec);
    av_free(picture);
    av_free(video_outbuf);
}
av_write_trailer(oc);
for (int i = 0; i < oc->nb_streams; i++) {
    av_freep(&oc->streams[i]->codec);
    av_freep(&oc->streams[i]);
}
if (!(fmt->flags & AVFMT_NOFILE)) {
    avio_close(oc->pb);
}
av_free(oc);

}

So can anyone find out the problem? Thanks very much!;

0

There are 0 best solutions below