2016-02-27 3 views
0

Я пытался кодировать фрейм с помощью FFmpeg с Visual C++. Вот как я это делаю. У меня сначала есть плоский буфер изображения RGB24. Я преобразовать его в планарной YUV, используя следующее правило:FFmpeg avcodec_encode_video2 нарушение прав доступа

Y = ((66 * R + 129 * G + 25 * B + 128) >> 8) + 16; 
U = ((-38 * R - 74 * G + 112 * B + 128) >> 8) + 128; 
V = ((112 * R - 94 * G - 18 * B + 128) >> 8) + 128; 

Я реализовал это следующим образом:

void rgb8toYuv(uchar* rgb, uchar* yuv, uint pixelAmount) { 
    uchar r, g, b; 
    for (uint i = 0; i < pixelAmount; i++) { 
     r = rgb[3 * i]; 
     g = rgb[3 * i + 1]; 
     b = rgb[3 * i + 2]; 
     yuv[3 * i] = ((66 * r + 129 * g + 25 * b + 128) >> 8) + 16; 
     yuv[3 * i + 1] = ((-38 * r - 74 * g + 112 * b + 128) >> 8) + 128; 
     yuv[3 * i + 2] = ((112 * r - 94 * g - 18 * b + 128) >> 8) + 128; 
    } 
} 

Я открываю все, как это (я использую таНос, потому что я привык к нему в C и это моя программа первого C++, я предполагаю, что это не должно вызывать никаких проблем):

AVCodec* codec = avcodec_find_encoder(AV_CODEC_ID_H264); 
AVFormatContext* outContext; 
avformat_alloc_output_context2(&outContext, NULL, "mp4", filepath); 

AVStream* video = avformat_new_stream(outContext, codec); 
video->codec->bit_rate = VIDEOBITRATE; 
video->codec->width = VIDEOWIDTH; 
video->codec->height = VIDEOHEIGHT; 
video->time_base = fps; 
video->codec->gop_size = 10; 
video->codec->max_b_frames = 1; 
video->codec->pix_fmt = AV_PIX_FMT_YUV420P; 
video->codec->codec_id = AV_CODEC_ID_H264; 
video->codec->codec_type = AVMEDIA_TYPE_VIDEO; 

avio_open(&outContext->pb, filepath, AVIO_FLAG_READ_WRITE); 
avformat_write_header(outContext, NULL); 

AVFrame* frame = av_frame_alloc(); 
frame->width = VIDEOWIDTH; 
frame->height = VIDEOHEIGHT; 
frame->format = AV_PIX_FMT_YUV420P; 

Тогда здесь функция Я использую для кодирования кадра:

void encodeFrame(uint currentFrame, uchar* data) { // RGB data 
    uchar* yuvData = (uchar*) malloc(videoWidth * videoHeight * 3); 
    rgb8toYuv(data, yuvData, videoWidth * videoHeight); 
    av_image_fill_arrays(frame->data, frame->linesize, yuvData, AV_PIX_FMT_YUV420P, videoWidth, videoHeight, 3); // I'm not sure about that 3, I couldn't find any documentation about it 

    AVPacket* packet = (AVPacket*) malloc(sizeof(AVPacket)); 
    memset(packet, 0, sizeof(AVPacket)); 
    av_init_packet(packet); 
    packet->data = NULL; 
    packet->size = 0; 

    frame->pts = currentFrame; // I don't know if this is corrrect too 
    avcodec_encode_video2(video->codec, packet, frame, NULL); 
    av_interleaved_write_frame(outContext, packet); 
    av_packet_unref(packet); 

    free(yuvData); 
    free(packet); 
} 

Однако это вызывает Access violation writing location 0x00000000 по адресу avcodec_encode_video2. Я проверил ошибки, возвращаемые каждой функцией FFmpeg, и кажется, что все они работают, кроме av_image_fill_arrays, который возвращает странную ошибку 1382400, хотя в соответствии с инструментом просмотра RAM отладчика все заполняется правильно.

Похоже, avcodec_encode_video2 пытается получить доступ к объекту NULL, которого не должно быть, однако я не могу найти, что это может быть, поскольку я следовал за множеством источников, и я не знаю, что я сделал неправильно ,

Заранее благодарен!

EDIT: После применения исправления, предложенное Эдгар Rokyan (который заходящий 4-ый аргумент указателя INT), теперь я получаю нарушение прав доступа на 0x00000024, по-прежнему с avformat_alloc_output_context2. Я считаю, что проблема схожа, но я все еще ничего не могу найти.

ответ

0

Необходимо позвонить по телефону avcodec_open2 до avcodec_encode_video2. Рекомендуется, чтобы вы не использовали контекст кодека в возвращаемом потоке от avformat_new_stream, но сначала сделайте копию его новой переменной, используя avcodec_alloc_context3 и avcodec_copy_context.

И не забудьте закрыть (avcodec_close) бесплатно (avcodec_free_context) когда закончите.

Смежные вопросы