[FFmpeg-user] avcodec_decode_video2 crash HEVC with get_buffer2
Никита Скиба
zaulan at gmail.com
Thu Feb 11 12:18:38 CET 2016
Hello to all!
Recently I have faced a problem with decoding hevc annexB stream. Crash
happens inside avcodec_decode_video2. I also use deprecated
get_buffer/release_buffer method to decrease memory copy operations count.
While decoding h264 or jpeg, or mpeg-4 there is no problems. Crash happens
only with hevc.
I assumed that reason of those crashes is in deprecated
get_buffer/release_buffer usage and tried to upgrade sources to get_buffer2
usage. But after upgrade decoder works well with h264 and still crashes on
hevc. Without get_buffer2 it decodes well.
Could you please point me to what I am doing wrong?
Sources of "upgraded" version of get_buffer2.
static void release_buffer2(void* opaque, uint8_t* data)
{
// pSample into opaque.
data[0] = 0;
data[1] = 0;
data[2] = 0;
if (0 != opaque)
{
Sample* pSample = (Sample*)(opaque);
pSample->Release();
}
}
static int get_buffer2(struct AVCodecContext *c, AVFrame *pic, int flags)
{
pic->width = c->width;
pic->height = c->height;
pic->format = c->pix_fmt;
CFFmpegAllocator* pObj = (CFFmpegAllocator*)(c->opaque);
return pObj ? pObj->get_buffer2_impl(c, pic, flags) : -1;
}
int get_buffer2_impl(AVCodecContext* avctx, AVFrame *pic, int flags)
{
int h_chroma_shift, v_chroma_shift;
int i, unaligned;
int size[4] = { 0 };
int offset[4] = { 0 };
if (!m_allocator)
{
return -1;
}
int w = pic->width,
h = pic->height;
const AVPixelFormat pix_fmt = static_cast<AVPixelFormat>(pic->format);
if (av_image_check_size(w, h, 0, NULL) < 0)
{
return -1;
}
avcodec_get_chroma_sub_sample(pix_fmt, &h_chroma_shift,
&v_chroma_shift);
// Maximum alignment required is for AVX; use it to be on the safe side
const int stride_align[4] = { 32, 32, 32, 32 };
{
// inlined stripped-down version of avcodec_align_dimensions2
const int PIXEL_PER_MACROBLOCK = 16; // assume 16 pixel
per macroblock
const int w_align = PIXEL_PER_MACROBLOCK;
const int h_align = PIXEL_PER_MACROBLOCK * 2; // interlaced needs
2 macroblocks height
w = FFALIGN(w, w_align);
h = FFALIGN(h, h_align);
}
do{
av_image_fill_linesizes(pic->linesize, pix_fmt, w);
w += w & ~(w - 1);
unaligned = 0;
for (i = 0; i < 4; i++){
unaligned |= pic->linesize[i] % stride_align[i];
}
} while (unaligned);
int image_size = av_image_fill_pointers(pic->data, pix_fmt,
h, NULL, pic->linesize);
if (image_size < 0)
return -1;
for (i = 0; i < 3 && pic->data[i + 1]; i++)
size[i] = pic->data[i + 1] - pic->data[i];
size[i] = image_size - (pic->data[i] - pic->data[0]);
image_size = 0;
for (i = 0; i < 4 && size[i]; ++i)
{
const int h_shift = (0 == i) ? 0 : h_chroma_shift;
const int v_shift = (0 == i) ? 0 : v_chroma_shift;
offset[i] = 0;
size[i] += 16; //16 bytes at the end of each plane
image_size += size[i] + offset[i];
}
Sample* pSample = m_allocator->Alloc(image_size);
if (!pSample)
{
return -1;
}
SampleHeader& header = pSample->Header();
header.BodySize = image_size;
uint8_t *body = pSample->GetBody();
pic->data[0] = body + offset[0];
pic->buf[0] = av_buffer_create(pic->data[0] + offset[0], size[0],
release_buffer2, NULL, 0);
for (i = 1; i < 4 && size[i]; ++i)
{
pic->data[i] = pic->data[i - 1] + size[i - 1] + offset[i];
pic->buf[i] = av_buffer_create(pic->data[i] + offset[i], size[i],
release_buffer2, NULL, 0);
}
#if (LIBAVCODEC_VERSION_MAJOR < 54)
pic->age = INT_MAX;
#endif
pic->type = FF_BUFFER_TYPE_USER;
pic->opaque = pSample;
return 0;
}
Looking forward to your answer,
Nikita
More information about the ffmpeg-user
mailing list