diff --git a/libcam/libcam_v4l2core/frame_decoder.c b/libcam/libcam_v4l2core/frame_decoder.c index 63366fa8..a5845b13 100644 --- a/libcam/libcam_v4l2core/frame_decoder.c +++ b/libcam/libcam_v4l2core/frame_decoder.c @@ -134,6 +134,7 @@ int alloc_v4l2_frames(v4l2_dev_t *vd) /*frame queue*/ for(i=0; iframe_queue_size; ++i) { + vd->frame_queue[i].yuv_frame_max_size = (size_t) framesizeIn; vd->frame_queue[i].yuv_frame = calloc((size_t) framesizeIn, sizeof(uint8_t)); if(vd->frame_queue[i].yuv_frame == NULL) { @@ -346,6 +347,7 @@ void clean_v4l2_frames(v4l2_dev_t *vd) free(vd->frame_queue[i].yuv_frame); vd->frame_queue[i].yuv_frame = NULL; } + vd->frame_queue[i].yuv_frame_max_size = 0; } if(vd->h264_last_IDR) @@ -828,6 +830,44 @@ int decode_v4l2_frame(v4l2_dev_t *vd, v4l2_frame_buff_t *frame) //} if(verbosity > 3) fprintf(stderr, "V4L2_CORE: (jpeg decoder) decode frame of size %i\n", ret); + if (ret >= 0) + { + int real_w = 0; + int real_h = 0; + if (jpeg_get_decoded_size(&real_w, &real_h) == 0 && + real_w > 0 && real_h > 0 && + (real_w != frame->width || real_h != frame->height)) + { + if(verbosity > 0) + fprintf(stderr, "V4L2_CORE: (jpeg decoder) frame size %dx%d != negotiated %dx%d, using real size\n", + real_w, real_h, frame->width, frame->height); + frame->width = real_w; + frame->height = real_h; + } + + if (real_w > 0 && real_h > 0) + { + size_t need = (size_t)real_w * (size_t)real_h * 3 / 2; + if (need > 0 && need != frame->yuv_frame_max_size) + { + uint8_t *p = (uint8_t *)realloc(frame->yuv_frame, need); + if (p) + { + frame->yuv_frame = p; + frame->yuv_frame_max_size = need; + if(verbosity > 0) + fprintf(stderr, "V4L2_CORE: (jpeg decoder) yuv_frame trimmed %dx%d (%zu bytes)\n", + real_w, real_h, need); + } + else + { + if(verbosity > 0) + fprintf(stderr, "V4L2_CORE: (jpeg decoder) realloc failed for yuv_frame, keep old size\n"); + return E_ALLOC_ERR; + } + } + } + } ret = E_OK; break; diff --git a/libcam/libcam_v4l2core/gviewv4l2core.h b/libcam/libcam_v4l2core/gviewv4l2core.h index 7d8c7098..85a0640a 100644 --- a/libcam/libcam_v4l2core/gviewv4l2core.h +++ b/libcam/libcam_v4l2core/gviewv4l2core.h @@ -256,6 +256,7 @@ typedef struct _v4l2_frame_buff_t { uint64_t timestamp; // captured frame timestamp uint8_t *raw_frame; // pointer to raw frame + size_t yuv_frame_max_size; //maximum size for decoded yuv frame (bytes); MJPG is trimmed to real decoded size after 1st frame uint8_t *yuv_frame; // pointer to decoded yuv frame uint8_t *h264_frame; // pointer to regular or demultiplexed h264 frame uint8_t *tmp_buffer; //temporary buffer used in decoding diff --git a/libcam/libcam_v4l2core/jpeg_decoder.c b/libcam/libcam_v4l2core/jpeg_decoder.c index cf65efa6..e3c8b1cc 100644 --- a/libcam/libcam_v4l2core/jpeg_decoder.c +++ b/libcam/libcam_v4l2core/jpeg_decoder.c @@ -1430,8 +1430,6 @@ int jpeg_init_decoder(int width, int height) } codec_data->context->pix_fmt = AV_PIX_FMT_YUV422P; - codec_data->context->width = width; - codec_data->context->height = height; //jpeg_ctx->context->dsp_mask = (FF_MM_MMX | FF_MM_MMXEXT | FF_MM_SSE); // Initialize hardware device context (VA-API) @@ -1582,9 +1580,26 @@ int jpeg_decode(uint8_t *out_buf, uint8_t *in_buf, int size) printf(" - %s\n", getAvutil()->m_av_get_pix_fmt_name((enum AVPixelFormat)AV_PIX_FMT_YUV420P)); } #if LIBAVUTIL_VER_AT_LEAST(54,6) - getAvutil()->m_av_image_copy_to_buffer(jpeg_ctx->tmp_frame, jpeg_ctx->pic_size, - (const uint8_t * const*) sw_frame->data, sw_frame->linesize, - sw_frame->format, jpeg_ctx->width, jpeg_ctx->height, 1); + { + int dec_w = sw_frame->width; + int dec_h = sw_frame->height; + int need = getAvutil()->m_av_image_get_buffer_size(sw_frame->format, dec_w, dec_h, 1); + if (need > 0 && (size_t)need > (size_t)jpeg_ctx->pic_size) { + uint8_t *p = realloc(jpeg_ctx->tmp_frame, (size_t)need); + if (!p) { + fprintf(stderr, "V4L2_CORE: (jpeg decoder) realloc failed for tmp_frame\n"); + getAvutil()->m_av_frame_free(&sw_frame); + return -1; + } + jpeg_ctx->tmp_frame = p; + jpeg_ctx->pic_size = need; + } + jpeg_ctx->width = dec_w; + jpeg_ctx->height = dec_h; + getAvutil()->m_av_image_copy_to_buffer(jpeg_ctx->tmp_frame, jpeg_ctx->pic_size, + (const uint8_t * const*) sw_frame->data, sw_frame->linesize, + sw_frame->format, dec_w, dec_h, 1); + } if (sw_frame->format == AV_PIX_FMT_NV12) { nv12_to_yu12(out_buf, jpeg_ctx->tmp_frame, jpeg_ctx->width, jpeg_ctx->height); getAvutil()->m_av_frame_free(&sw_frame); @@ -1609,9 +1624,26 @@ int jpeg_decode(uint8_t *out_buf, uint8_t *in_buf, int size) } decodeCount++; } - getAvutil()->m_av_image_copy_to_buffer(jpeg_ctx->tmp_frame, jpeg_ctx->pic_size, - (const uint8_t * const*) codec_data->picture->data, codec_data->picture->linesize, - codec_data->context->pix_fmt, jpeg_ctx->width, jpeg_ctx->height, 1); + { + int dec_w = codec_data->picture->width; + int dec_h = codec_data->picture->height; + enum AVPixelFormat dec_fmt = codec_data->picture->format; + int need = getAvutil()->m_av_image_get_buffer_size(dec_fmt, dec_w, dec_h, 1); + if (need > 0 && (size_t)need > (size_t)jpeg_ctx->pic_size) { + uint8_t *p = realloc(jpeg_ctx->tmp_frame, (size_t)need); + if (!p) { + fprintf(stderr, "V4L2_CORE: (jpeg decoder) realloc failed for tmp_frame\n"); + return -1; + } + jpeg_ctx->tmp_frame = p; + jpeg_ctx->pic_size = need; + } + jpeg_ctx->width = dec_w; + jpeg_ctx->height = dec_h; + getAvutil()->m_av_image_copy_to_buffer(jpeg_ctx->tmp_frame, jpeg_ctx->pic_size, + (const uint8_t * const*) codec_data->picture->data, codec_data->picture->linesize, + dec_fmt, dec_w, dec_h, 1); + } #else avpicture_layout((AVPicture *) codec_data->picture, codec_data->dec_ctx->pix_fmt, jpeg_ctx->width, jpeg_ctx->height, jpeg_ctx->tmp_frame, jpeg_ctx->pic_size); @@ -1640,6 +1672,27 @@ int jpeg_decode(uint8_t *out_buf, uint8_t *in_buf, int size) } +/* + * get real (decoded) frame size + * args: + * out_w - pointer to receive real decoded width (may be NULL) + * out_h - pointer to receive real decoded height (may be NULL) + * + * asserts: + * none + * + * returns: 0 on success (valid size available); negative if not initialized + * or not decoded yet + */ +int jpeg_get_decoded_size(int *out_w, int *out_h) +{ + if (jpeg_ctx == NULL || jpeg_ctx->width <= 0 || jpeg_ctx->height <= 0) + return -1; + if (out_w) *out_w = jpeg_ctx->width; + if (out_h) *out_h = jpeg_ctx->height; + return 0; +} + /* * close (m)jpeg decoder context * args: diff --git a/libcam/libcam_v4l2core/jpeg_decoder.h b/libcam/libcam_v4l2core/jpeg_decoder.h index f3fa8102..f9aa7ced 100644 --- a/libcam/libcam_v4l2core/jpeg_decoder.h +++ b/libcam/libcam_v4l2core/jpeg_decoder.h @@ -75,6 +75,16 @@ int jpeg_init_decoder(int width, int height); */ int jpeg_decode(uint8_t *out_buf, uint8_t *in_buf, int size); +/* + * get real (decoded) frame size after jpeg_decode() + * args: + * out_w - pointer to receive real decoded width (may be NULL) + * out_h - pointer to receive real decoded height (may be NULL) + * + * returns: 0 - OK; negative - not initialized or not decoded yet + */ +int jpeg_get_decoded_size(int *out_w, int *out_h); + /* * close (m)jpeg decoder context * args: