summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--build/make/configure.sh4
-rw-r--r--test/resize_test.cc4
-rw-r--r--test/vp9_ext_ratectrl_test.cc18
-rw-r--r--test/y4m_test.cc25
-rw-r--r--vp8/encoder/encodeframe.c5
-rw-r--r--vp9/encoder/vp9_encoder.c41
-rw-r--r--vp9/encoder/vp9_ext_ratectrl.c101
-rw-r--r--vp9/encoder/vp9_ext_ratectrl.h28
-rw-r--r--vp9/encoder/vp9_firstpass.c4
-rw-r--r--vp9/simple_encode.cc10
-rw-r--r--vp9/simple_encode.h43
-rw-r--r--vp9/vp9_cx_iface.c6
-rw-r--r--vpx/vpx_encoder.h4
-rw-r--r--vpx/vpx_ext_ratectrl.h227
-rw-r--r--vpx_dsp/arm/highbd_loopfilter_neon.c15
-rw-r--r--vpx_dsp/arm/loopfilter_neon.c15
-rw-r--r--vpxenc.c11
-rw-r--r--y4minput.c394
-rw-r--r--y4minput.h12
19 files changed, 667 insertions, 300 deletions
diff --git a/build/make/configure.sh b/build/make/configure.sh
index 91a64b504..c4e938fc7 100644
--- a/build/make/configure.sh
+++ b/build/make/configure.sh
@@ -919,8 +919,8 @@ process_common_toolchain() {
add_ldflags "-mmacosx-version-min=10.15"
;;
*-darwin20-*)
- add_cflags "-mmacosx-version-min=10.16"
- add_ldflags "-mmacosx-version-min=10.16"
+ add_cflags "-mmacosx-version-min=10.16 -arch ${toolchain%%-*}"
+ add_ldflags "-mmacosx-version-min=10.16 -arch ${toolchain%%-*}"
;;
*-iphonesimulator-*)
add_cflags "-miphoneos-version-min=${IOS_VERSION_MIN}"
diff --git a/test/resize_test.cc b/test/resize_test.cc
index 65b94fa4f..c57170ff9 100644
--- a/test/resize_test.cc
+++ b/test/resize_test.cc
@@ -271,8 +271,8 @@ class ResizingVideoSource : public ::libvpx_test::DummyVideoSource {
protected:
virtual void Next() {
++frame_;
- unsigned int width;
- unsigned int height;
+ unsigned int width = 0;
+ unsigned int height = 0;
ScaleForFrameNumber(frame_, kInitialWidth, kInitialHeight, &width, &height,
flag_codec_, smaller_width_larger_size_);
SetSize(width, height);
diff --git a/test/vp9_ext_ratectrl_test.cc b/test/vp9_ext_ratectrl_test.cc
index 8db0a358d..4b3693a34 100644
--- a/test/vp9_ext_ratectrl_test.cc
+++ b/test/vp9_ext_ratectrl_test.cc
@@ -44,7 +44,7 @@ vpx_rc_status_t rc_create_model(void *priv,
EXPECT_EQ(ratectrl_config->target_bitrate_kbps, 24000);
EXPECT_EQ(ratectrl_config->frame_rate_num, 30);
EXPECT_EQ(ratectrl_config->frame_rate_den, 1);
- return vpx_rc_ok;
+ return VPX_RC_OK;
}
vpx_rc_status_t rc_send_firstpass_stats(
@@ -57,7 +57,7 @@ vpx_rc_status_t rc_send_firstpass_stats(
for (int i = 0; i < first_pass_stats->num_frames; ++i) {
EXPECT_DOUBLE_EQ(first_pass_stats->frame_stats[i].frame, i);
}
- return vpx_rc_ok;
+ return VPX_RC_OK;
}
vpx_rc_status_t rc_get_encodeframe_decision(
@@ -73,6 +73,8 @@ vpx_rc_status_t rc_get_encodeframe_decision(
EXPECT_EQ(encode_frame_info->coding_index, toy_rate_ctrl->coding_index);
if (encode_frame_info->coding_index == 0) {
+ EXPECT_EQ(encode_frame_info->show_index, 0);
+ EXPECT_EQ(encode_frame_info->gop_index, 0);
EXPECT_EQ(encode_frame_info->frame_type, 0 /*kFrameTypeKey*/);
EXPECT_EQ(encode_frame_info->ref_frame_valid_list[0],
0); // kRefFrameTypeLast
@@ -83,6 +85,8 @@ vpx_rc_status_t rc_get_encodeframe_decision(
}
if (encode_frame_info->coding_index == 1) {
+ EXPECT_EQ(encode_frame_info->show_index, 4);
+ EXPECT_EQ(encode_frame_info->gop_index, 1);
EXPECT_EQ(encode_frame_info->frame_type, 2 /*kFrameTypeAltRef*/);
EXPECT_EQ(encode_frame_info->ref_frame_valid_list[0],
1); // kRefFrameTypeLast
@@ -96,10 +100,14 @@ vpx_rc_status_t rc_get_encodeframe_decision(
if (encode_frame_info->coding_index >= 2 &&
encode_frame_info->coding_index < 5) {
+ // In the first group of pictures, coding_index and gop_index are equal.
+ EXPECT_EQ(encode_frame_info->gop_index, encode_frame_info->coding_index);
EXPECT_EQ(encode_frame_info->frame_type, 1 /*kFrameTypeInter*/);
}
if (encode_frame_info->coding_index == 5) {
+ EXPECT_EQ(encode_frame_info->show_index, 4);
+ EXPECT_EQ(encode_frame_info->gop_index, 0);
EXPECT_EQ(encode_frame_info->frame_type, 3 /*kFrameTypeOverlay*/);
EXPECT_EQ(encode_frame_info->ref_frame_valid_list[0],
1); // kRefFrameTypeLast
@@ -120,7 +128,7 @@ vpx_rc_status_t rc_get_encodeframe_decision(
} else {
frame_decision->q_index = 100;
}
- return vpx_rc_ok;
+ return VPX_RC_OK;
}
vpx_rc_status_t rc_update_encodeframe_result(
@@ -135,14 +143,14 @@ vpx_rc_status_t rc_update_encodeframe_result(
if (toy_rate_ctrl->coding_index == kLosslessCodingIndex) {
EXPECT_EQ(encode_frame_result->sse, 0);
}
- return vpx_rc_ok;
+ return VPX_RC_OK;
}
vpx_rc_status_t rc_delete_model(vpx_rc_model_t rate_ctrl_model) {
ToyRateCtrl *toy_rate_ctrl = static_cast<ToyRateCtrl *>(rate_ctrl_model);
EXPECT_EQ(toy_rate_ctrl->magic_number, kModelMagicNumber);
delete toy_rate_ctrl;
- return vpx_rc_ok;
+ return VPX_RC_OK;
}
class ExtRateCtrlTest : public ::libvpx_test::EncoderTest,
diff --git a/test/y4m_test.cc b/test/y4m_test.cc
index 46cb5cff8..5df389f52 100644
--- a/test/y4m_test.cc
+++ b/test/y4m_test.cc
@@ -188,4 +188,29 @@ TEST_P(Y4mVideoWriteTest, WriteTest) {
INSTANTIATE_TEST_SUITE_P(C, Y4mVideoWriteTest,
::testing::ValuesIn(kY4mTestVectors));
+
+static const char kY4MRegularHeader[] =
+ "YUV4MPEG2 W4 H4 F30:1 Ip A0:0 C420jpeg XYSCSS=420JPEG\n"
+ "FRAME\n"
+ "012345678912345601230123";
+
+TEST(Y4MHeaderTest, RegularHeader) {
+ libvpx_test::TempOutFile f;
+ fwrite(kY4MRegularHeader, 1, sizeof(kY4MRegularHeader), f.file());
+ fflush(f.file());
+ EXPECT_EQ(0, fseek(f.file(), 0, 0));
+
+ y4m_input y4m;
+ EXPECT_EQ(y4m_input_open(&y4m, f.file(), /*skip_buffer=*/NULL,
+ /*num_skip=*/0, /*only_420=*/0),
+ 0);
+ EXPECT_EQ(y4m.pic_w, 4);
+ EXPECT_EQ(y4m.pic_h, 4);
+ EXPECT_EQ(y4m.fps_n, 30);
+ EXPECT_EQ(y4m.fps_d, 1);
+ EXPECT_EQ(y4m.interlace, 'p');
+ EXPECT_EQ(strcmp("420jpeg", y4m.chroma_type), 0);
+ y4m_input_close(&y4m);
+}
+
} // namespace
diff --git a/vp8/encoder/encodeframe.c b/vp8/encoder/encodeframe.c
index 2b3d9564c..2f84381d2 100644
--- a/vp8/encoder/encodeframe.c
+++ b/vp8/encoder/encodeframe.c
@@ -343,8 +343,11 @@ static void encode_mb_row(VP8_COMP *cpi, VP8_COMMON *cm, int mb_row,
const int nsync = cpi->mt_sync_range;
vpx_atomic_int rightmost_col = VPX_ATOMIC_INIT(cm->mb_cols + nsync);
const vpx_atomic_int *last_row_current_mb_col;
- vpx_atomic_int *current_mb_col = &cpi->mt_current_mb_col[mb_row];
+ vpx_atomic_int *current_mb_col = NULL;
+ if (vpx_atomic_load_acquire(&cpi->b_multi_threaded) != 0) {
+ current_mb_col = &cpi->mt_current_mb_col[mb_row];
+ }
if (vpx_atomic_load_acquire(&cpi->b_multi_threaded) != 0 && mb_row != 0) {
last_row_current_mb_col = &cpi->mt_current_mb_col[mb_row - 1];
} else {
diff --git a/vp9/encoder/vp9_encoder.c b/vp9/encoder/vp9_encoder.c
index 4750f5b7b..6a21a1c18 100644
--- a/vp9/encoder/vp9_encoder.c
+++ b/vp9/encoder/vp9_encoder.c
@@ -2464,7 +2464,12 @@ VP9_COMP *vp9_create_compressor(const VP9EncoderConfig *oxcf,
cpi->allow_encode_breakout = ENCODE_BREAKOUT_ENABLED;
- vp9_extrc_init(&cpi->ext_ratectrl);
+ {
+ vpx_codec_err_t codec_status = vp9_extrc_init(&cpi->ext_ratectrl);
+ if (codec_status != VPX_CODEC_OK) {
+ vpx_internal_error(&cm->error, codec_status, "vp9_extrc_init() failed");
+ }
+ }
#if !CONFIG_REALTIME_ONLY
if (oxcf->pass == 1) {
@@ -4503,16 +4508,23 @@ static void encode_with_recode_loop(VP9_COMP *cpi, size_t *size, uint8_t *dest
}
#endif
if (cpi->ext_ratectrl.ready) {
+ vpx_codec_err_t codec_status;
const GF_GROUP *gf_group = &cpi->twopass.gf_group;
vpx_rc_encodeframe_decision_t encode_frame_decision;
FRAME_UPDATE_TYPE update_type = gf_group->update_type[gf_group->index];
const int ref_frame_flags = get_ref_frame_flags(cpi);
RefCntBuffer *ref_frame_bufs[MAX_INTER_REF_FRAMES];
+ const RefCntBuffer *curr_frame_buf =
+ get_ref_cnt_buffer(cm, cm->new_fb_idx);
get_ref_frame_bufs(cpi, ref_frame_bufs);
- vp9_extrc_get_encodeframe_decision(
- &cpi->ext_ratectrl, cm->current_video_frame,
- cm->current_frame_coding_index, update_type, ref_frame_bufs,
- ref_frame_flags, &encode_frame_decision);
+ codec_status = vp9_extrc_get_encodeframe_decision(
+ &cpi->ext_ratectrl, curr_frame_buf->frame_index,
+ cm->current_frame_coding_index, gf_group->index, update_type,
+ ref_frame_bufs, ref_frame_flags, &encode_frame_decision);
+ if (codec_status != VPX_CODEC_OK) {
+ vpx_internal_error(&cm->error, codec_status,
+ "vp9_extrc_get_encodeframe_decision() failed");
+ }
q = encode_frame_decision.q_index;
}
@@ -5487,9 +5499,13 @@ static void encode_frame_to_data_rate(
{
const RefCntBuffer *coded_frame_buf =
get_ref_cnt_buffer(cm, cm->new_fb_idx);
- vp9_extrc_update_encodeframe_result(
+ vpx_codec_err_t codec_status = vp9_extrc_update_encodeframe_result(
&cpi->ext_ratectrl, (*size) << 3, cpi->Source, &coded_frame_buf->buf,
cm->bit_depth, cpi->oxcf.input_bit_depth);
+ if (codec_status != VPX_CODEC_OK) {
+ vpx_internal_error(&cm->error, codec_status,
+ "vp9_extrc_update_encodeframe_result() failed");
+ }
}
#if CONFIG_REALTIME_ONLY
(void)encode_frame_result;
@@ -5680,8 +5696,13 @@ static void Pass2Encode(VP9_COMP *cpi, size_t *size, uint8_t *dest,
cpi->allow_encode_breakout = ENCODE_BREAKOUT_ENABLED;
if (cpi->common.current_frame_coding_index == 0) {
- vp9_extrc_send_firstpass_stats(&cpi->ext_ratectrl,
- &cpi->twopass.first_pass_info);
+ VP9_COMMON *cm = &cpi->common;
+ const vpx_codec_err_t codec_status = vp9_extrc_send_firstpass_stats(
+ &cpi->ext_ratectrl, &cpi->twopass.first_pass_info);
+ if (codec_status != VPX_CODEC_OK) {
+ vpx_internal_error(&cm->error, codec_status,
+ "vp9_extrc_send_firstpass_stats() failed");
+ }
}
#if CONFIG_MISMATCH_DEBUG
mismatch_move_frame_idx_w();
@@ -7383,8 +7404,6 @@ static void accumulate_frame_tpl_stats(VP9_COMP *cpi) {
// Accumulate tpl stats for each frame in the current group of picture.
for (frame_idx = 1; frame_idx < gf_group->gf_group_size; ++frame_idx) {
TplDepFrame *tpl_frame = &cpi->tpl_stats[frame_idx];
- if (!tpl_frame->is_valid) continue;
-
TplDepStats *tpl_stats = tpl_frame->tpl_stats_ptr;
const int tpl_stride = tpl_frame->stride;
int64_t intra_cost_base = 0;
@@ -7394,6 +7413,8 @@ static void accumulate_frame_tpl_stats(VP9_COMP *cpi) {
int64_t mc_flow_base = 0;
int row, col;
+ if (!tpl_frame->is_valid) continue;
+
for (row = 0; row < cm->mi_rows && tpl_frame->is_valid; ++row) {
for (col = 0; col < cm->mi_cols; ++col) {
TplDepStats *this_stats = &tpl_stats[row * tpl_stride + col];
diff --git a/vp9/encoder/vp9_ext_ratectrl.c b/vp9/encoder/vp9_ext_ratectrl.c
index 94c2addd2..a27eb653b 100644
--- a/vp9/encoder/vp9_ext_ratectrl.c
+++ b/vp9/encoder/vp9_ext_ratectrl.c
@@ -13,31 +13,56 @@
#include "vp9/common/vp9_common.h"
#include "vpx_dsp/psnr.h"
-void vp9_extrc_init(EXT_RATECTRL *ext_ratectrl) { vp9_zero(*ext_ratectrl); }
+vpx_codec_err_t vp9_extrc_init(EXT_RATECTRL *ext_ratectrl) {
+ if (ext_ratectrl == NULL) {
+ return VPX_CODEC_INVALID_PARAM;
+ }
+ vp9_zero(*ext_ratectrl);
+ return VPX_CODEC_OK;
+}
-void vp9_extrc_create(vpx_rc_funcs_t funcs, vpx_rc_config_t ratectrl_config,
- EXT_RATECTRL *ext_ratectrl) {
+vpx_codec_err_t vp9_extrc_create(vpx_rc_funcs_t funcs,
+ vpx_rc_config_t ratectrl_config,
+ EXT_RATECTRL *ext_ratectrl) {
+ vpx_rc_status_t rc_status;
vpx_rc_firstpass_stats_t *rc_firstpass_stats;
+ if (ext_ratectrl == NULL) {
+ return VPX_CODEC_INVALID_PARAM;
+ }
vp9_extrc_delete(ext_ratectrl);
ext_ratectrl->funcs = funcs;
ext_ratectrl->ratectrl_config = ratectrl_config;
- ext_ratectrl->funcs.create_model(ext_ratectrl->funcs.priv,
- &ext_ratectrl->ratectrl_config,
- &ext_ratectrl->model);
+ rc_status = ext_ratectrl->funcs.create_model(ext_ratectrl->funcs.priv,
+ &ext_ratectrl->ratectrl_config,
+ &ext_ratectrl->model);
+ if (rc_status == VPX_RC_ERROR) {
+ return VPX_CODEC_ERROR;
+ }
rc_firstpass_stats = &ext_ratectrl->rc_firstpass_stats;
rc_firstpass_stats->num_frames = ratectrl_config.show_frame_count;
rc_firstpass_stats->frame_stats =
vpx_malloc(sizeof(*rc_firstpass_stats->frame_stats) *
rc_firstpass_stats->num_frames);
+ if (rc_firstpass_stats->frame_stats == NULL) {
+ return VPX_CODEC_MEM_ERROR;
+ }
ext_ratectrl->ready = 1;
+ return VPX_CODEC_OK;
}
-void vp9_extrc_delete(EXT_RATECTRL *ext_ratectrl) {
+vpx_codec_err_t vp9_extrc_delete(EXT_RATECTRL *ext_ratectrl) {
+ if (ext_ratectrl == NULL) {
+ return VPX_CODEC_INVALID_PARAM;
+ }
if (ext_ratectrl->ready) {
- ext_ratectrl->funcs.delete_model(ext_ratectrl->model);
+ vpx_rc_status_t rc_status =
+ ext_ratectrl->funcs.delete_model(ext_ratectrl->model);
+ if (rc_status == VPX_RC_ERROR) {
+ return VPX_CODEC_ERROR;
+ }
vpx_free(ext_ratectrl->rc_firstpass_stats.frame_stats);
}
- vp9_extrc_init(ext_ratectrl);
+ return vp9_extrc_init(ext_ratectrl);
}
static void gen_rc_firstpass_stats(const FIRSTPASS_STATS *stats,
@@ -69,9 +94,13 @@ static void gen_rc_firstpass_stats(const FIRSTPASS_STATS *stats,
rc_frame_stats->count = stats->count;
}
-void vp9_extrc_send_firstpass_stats(EXT_RATECTRL *ext_ratectrl,
- const FIRST_PASS_INFO *first_pass_info) {
+vpx_codec_err_t vp9_extrc_send_firstpass_stats(
+ EXT_RATECTRL *ext_ratectrl, const FIRST_PASS_INFO *first_pass_info) {
+ if (ext_ratectrl == NULL) {
+ return VPX_CODEC_INVALID_PARAM;
+ }
if (ext_ratectrl->ready) {
+ vpx_rc_status_t rc_status;
vpx_rc_firstpass_stats_t *rc_firstpass_stats =
&ext_ratectrl->rc_firstpass_stats;
int i;
@@ -80,9 +109,13 @@ void vp9_extrc_send_firstpass_stats(EXT_RATECTRL *ext_ratectrl,
gen_rc_firstpass_stats(&first_pass_info->stats[i],
&rc_firstpass_stats->frame_stats[i]);
}
- ext_ratectrl->funcs.send_firstpass_stats(ext_ratectrl->model,
- rc_firstpass_stats);
+ rc_status = ext_ratectrl->funcs.send_firstpass_stats(ext_ratectrl->model,
+ rc_firstpass_stats);
+ if (rc_status == VPX_RC_ERROR) {
+ return VPX_CODEC_ERROR;
+ }
}
+ return VPX_CODEC_OK;
}
static int extrc_get_frame_type(FRAME_UPDATE_TYPE update_type) {
@@ -102,39 +135,51 @@ static int extrc_get_frame_type(FRAME_UPDATE_TYPE update_type) {
}
}
-void vp9_extrc_get_encodeframe_decision(
- EXT_RATECTRL *ext_ratectrl, int show_index, int coding_index,
+vpx_codec_err_t vp9_extrc_get_encodeframe_decision(
+ EXT_RATECTRL *ext_ratectrl, int show_index, int coding_index, int gop_index,
FRAME_UPDATE_TYPE update_type,
RefCntBuffer *ref_frame_bufs[MAX_INTER_REF_FRAMES], int ref_frame_flags,
vpx_rc_encodeframe_decision_t *encode_frame_decision) {
+ if (ext_ratectrl == NULL) {
+ return VPX_CODEC_INVALID_PARAM;
+ }
if (ext_ratectrl->ready) {
+ vpx_rc_status_t rc_status;
vpx_rc_encodeframe_info_t encode_frame_info;
encode_frame_info.show_index = show_index;
encode_frame_info.coding_index = coding_index;
+ encode_frame_info.gop_index = gop_index;
encode_frame_info.frame_type = extrc_get_frame_type(update_type);
vp9_get_ref_frame_info(update_type, ref_frame_flags, ref_frame_bufs,
encode_frame_info.ref_frame_coding_indexes,
encode_frame_info.ref_frame_valid_list);
- ext_ratectrl->funcs.get_encodeframe_decision(
+ rc_status = ext_ratectrl->funcs.get_encodeframe_decision(
ext_ratectrl->model, &encode_frame_info, encode_frame_decision);
+ if (rc_status == VPX_RC_ERROR) {
+ return VPX_CODEC_ERROR;
+ }
}
+ return VPX_CODEC_OK;
}
-void vp9_extrc_update_encodeframe_result(EXT_RATECTRL *ext_ratectrl,
- int64_t bit_count,
- const YV12_BUFFER_CONFIG *source_frame,
- const YV12_BUFFER_CONFIG *coded_frame,
- uint32_t bit_depth,
- uint32_t input_bit_depth) {
+vpx_codec_err_t vp9_extrc_update_encodeframe_result(
+ EXT_RATECTRL *ext_ratectrl, int64_t bit_count,
+ const YV12_BUFFER_CONFIG *source_frame,
+ const YV12_BUFFER_CONFIG *coded_frame, uint32_t bit_depth,
+ uint32_t input_bit_depth) {
+ if (ext_ratectrl == NULL) {
+ return VPX_CODEC_INVALID_PARAM;
+ }
if (ext_ratectrl->ready) {
PSNR_STATS psnr;
+ vpx_rc_status_t rc_status;
vpx_rc_encodeframe_result_t encode_frame_result;
encode_frame_result.bit_count = bit_count;
encode_frame_result.pixel_count =
- source_frame->y_width * source_frame->y_height +
- 2 * source_frame->uv_width * source_frame->uv_height;
+ source_frame->y_crop_width * source_frame->y_crop_height +
+ 2 * source_frame->uv_crop_width * source_frame->uv_crop_height;
#if CONFIG_VP9_HIGHBITDEPTH
vpx_calc_highbd_psnr(source_frame, coded_frame, &psnr, bit_depth,
input_bit_depth);
@@ -144,7 +189,11 @@ void vp9_extrc_update_encodeframe_result(EXT_RATECTRL *ext_ratectrl,
vpx_calc_psnr(source_frame, coded_frame, &psnr);
#endif
encode_frame_result.sse = psnr.sse[0];
- ext_ratectrl->funcs.update_encodeframe_result(ext_ratectrl->model,
- &encode_frame_result);
+ rc_status = ext_ratectrl->funcs.update_encodeframe_result(
+ ext_ratectrl->model, &encode_frame_result);
+ if (rc_status == VPX_RC_ERROR) {
+ return VPX_CODEC_ERROR;
+ }
}
+ return VPX_CODEC_OK;
}
diff --git a/vp9/encoder/vp9_ext_ratectrl.h b/vp9/encoder/vp9_ext_ratectrl.h
index fb6cfe1ac..11e9102a6 100644
--- a/vp9/encoder/vp9_ext_ratectrl.h
+++ b/vp9/encoder/vp9_ext_ratectrl.h
@@ -22,27 +22,27 @@ typedef struct EXT_RATECTRL {
vpx_rc_firstpass_stats_t rc_firstpass_stats;
} EXT_RATECTRL;
-void vp9_extrc_init(EXT_RATECTRL *ext_ratectrl);
+vpx_codec_err_t vp9_extrc_init(EXT_RATECTRL *ext_ratectrl);
-void vp9_extrc_create(vpx_rc_funcs_t funcs, vpx_rc_config_t ratectrl_config,
- EXT_RATECTRL *ext_ratectrl);
+vpx_codec_err_t vp9_extrc_create(vpx_rc_funcs_t funcs,
+ vpx_rc_config_t ratectrl_config,
+ EXT_RATECTRL *ext_ratectrl);
-void vp9_extrc_delete(EXT_RATECTRL *ext_ratectrl);
+vpx_codec_err_t vp9_extrc_delete(EXT_RATECTRL *ext_ratectrl);
-void vp9_extrc_send_firstpass_stats(EXT_RATECTRL *ext_ratectrl,
- const FIRST_PASS_INFO *first_pass_info);
+vpx_codec_err_t vp9_extrc_send_firstpass_stats(
+ EXT_RATECTRL *ext_ratectrl, const FIRST_PASS_INFO *first_pass_info);
-void vp9_extrc_get_encodeframe_decision(
- EXT_RATECTRL *ext_ratectrl, int show_index, int coding_index,
+vpx_codec_err_t vp9_extrc_get_encodeframe_decision(
+ EXT_RATECTRL *ext_ratectrl, int show_index, int coding_index, int gop_index,
FRAME_UPDATE_TYPE update_type,
RefCntBuffer *ref_frame_bufs[MAX_INTER_REF_FRAMES], int ref_frame_flags,
vpx_rc_encodeframe_decision_t *encode_frame_decision);
-void vp9_extrc_update_encodeframe_result(EXT_RATECTRL *ext_ratectrl,
- int64_t bit_count,
- const YV12_BUFFER_CONFIG *source_frame,
- const YV12_BUFFER_CONFIG *coded_frame,
- uint32_t bit_depth,
- uint32_t input_bit_depth);
+vpx_codec_err_t vp9_extrc_update_encodeframe_result(
+ EXT_RATECTRL *ext_ratectrl, int64_t bit_count,
+ const YV12_BUFFER_CONFIG *source_frame,
+ const YV12_BUFFER_CONFIG *coded_frame, uint32_t bit_depth,
+ uint32_t input_bit_depth);
#endif // VPX_VP9_ENCODER_VP9_EXT_RATECTRL_H_
diff --git a/vp9/encoder/vp9_firstpass.c b/vp9/encoder/vp9_firstpass.c
index de954f757..2a9cf5289 100644
--- a/vp9/encoder/vp9_firstpass.c
+++ b/vp9/encoder/vp9_firstpass.c
@@ -1081,8 +1081,8 @@ void vp9_first_pass_encode_tile_mb_row(VP9_COMP *cpi, ThreadData *td,
x->mv_limits.col_max =
((cm->mb_cols - 1 - mb_col) * 16) + BORDER_MV_PIXELS_B16;
- // Other than for the first frame do a motion search.
- if (cm->current_video_frame > 0) {
+ // Other than for intra-only frame do a motion search.
+ if (!frame_is_intra_only(cm)) {
int tmp_err, motion_error, this_motion_error, raw_motion_error;
// Assume 0,0 motion with no mv overhead.
MV mv = { 0, 0 }, tmp_mv = { 0, 0 };
diff --git a/vp9/simple_encode.cc b/vp9/simple_encode.cc
index afda6e203..d4eb0c669 100644
--- a/vp9/simple_encode.cc
+++ b/vp9/simple_encode.cc
@@ -765,6 +765,16 @@ static void UpdateEncodeConfig(const EncodeConfig &config,
SET_STRUCT_VALUE(config, oxcf, ret, encode_breakout);
SET_STRUCT_VALUE(config, oxcf, ret, enable_tpl_model);
SET_STRUCT_VALUE(config, oxcf, ret, enable_auto_arf);
+ if (strcmp(config.name, "rc_mode") == 0) {
+ int rc_mode = atoi(config.value);
+ if (rc_mode >= VPX_VBR && rc_mode <= VPX_Q) {
+ oxcf->rc_mode = (enum vpx_rc_mode)rc_mode;
+ ret = 1;
+ } else {
+ fprintf(stderr, "Invalid rc_mode value: %d\n", rc_mode);
+ }
+ }
+ SET_STRUCT_VALUE(config, oxcf, ret, cq_level);
if (ret == 0) {
fprintf(stderr, "Ignored unsupported encode_config %s\n", config.name);
}
diff --git a/vp9/simple_encode.h b/vp9/simple_encode.h
index 380e8118f..8ec7069e8 100644
--- a/vp9/simple_encode.h
+++ b/vp9/simple_encode.h
@@ -281,7 +281,7 @@ struct EncodeFrameResult {
std::vector<MotionVectorInfo> motion_vector_info;
// A vector of the tpl stats information.
// The tpl stats measure the complexity of a frame, as well as the
- // informatioin propagated along the motion trajactory between frames, in
+ // information propagated along the motion trajectory between frames, in
// the reference frame structure.
// The tpl stats could be used as a more accurate spatial and temporal
// complexity measure in addition to the first pass stats.
@@ -361,21 +361,32 @@ class SimpleEncode {
// The following configs in VP9EncoderConfig are allowed to change in this
// function. See https://ffmpeg.org/ffmpeg-codecs.html#libvpx for each
// config's meaning.
- // Configs in VP9EncoderConfig: Equivalent configs in ffmpeg:
- // 1 key_freq -g
- // 2 two_pass_vbrmin_section -minrate * 100LL / bit_rate
- // 3 two_pass_vbrmax_section -maxrate * 100LL / bit_rate
- // 4 under_shoot_pct -undershoot-pct
- // 5 over_shoot_pct -overshoot-pct
- // 6 max_threads -threads
- // 7 frame_parallel_decoding_mode -frame-parallel
- // 8 tile_column -tile-columns
- // 9 arnr_max_frames -arnr-maxframes
- // 10 arnr_strength -arnr-strength
- // 11 lag_in_frames -rc_lookahead
- // 12 encode_breakout -static-thresh
- // 13 enable_tpl_model -enable-tpl
- // 14 enable_auto_arf -auto-alt-ref
+ // Configs in VP9EncoderConfig: Equivalent configs in ffmpeg:
+ // 1 key_freq -g
+ // 2 two_pass_vbrmin_section -minrate * 100LL / bit_rate
+ // 3 two_pass_vbrmax_section -maxrate * 100LL / bit_rate
+ // 4 under_shoot_pct -undershoot-pct
+ // 5 over_shoot_pct -overshoot-pct
+ // 6 max_threads -threads
+ // 7 frame_parallel_decoding_mode -frame-parallel
+ // 8 tile_column -tile-columns
+ // 9 arnr_max_frames -arnr-maxframes
+ // 10 arnr_strength -arnr-strength
+ // 11 lag_in_frames -rc_lookahead
+ // 12 encode_breakout -static-thresh
+ // 13 enable_tpl_model -enable-tpl
+ // 14 enable_auto_arf -auto-alt-ref
+ // 15 rc_mode
+ // Possible Settings:
+ // 0 - Variable Bit Rate (VPX_VBR) -b:v <bit_rate>
+ // 1 - Constant Bit Rate (VPX_CBR) -b:v <bit_rate> -minrate <bit_rate>
+ // -maxrate <bit_rate>
+ // two_pass_vbrmin_section == 100 i.e. bit_rate == minrate == maxrate
+ // two_pass_vbrmax_section == 100
+ // 2 - Constrained Quality (VPX_CQ) -crf <cq_level> -b:v bit_rate
+ // 3 - Constant Quality (VPX_Q) -crf <cq_level> -b:v 0
+ // See https://trac.ffmpeg.org/wiki/Encode/VP9 for more details.
+ // 16 cq_level see rc_mode for details.
StatusCode SetEncodeConfig(const char *name, const char *value);
// A debug function that dumps configs from VP9EncoderConfig
diff --git a/vp9/vp9_cx_iface.c b/vp9/vp9_cx_iface.c
index a73683dfe..ecfacfaf4 100644
--- a/vp9/vp9_cx_iface.c
+++ b/vp9/vp9_cx_iface.c
@@ -1744,6 +1744,7 @@ static vpx_codec_err_t ctrl_set_external_rate_control(vpx_codec_alg_priv_t *ctx,
if (oxcf->pass == 2) {
const FRAME_INFO *frame_info = &cpi->frame_info;
vpx_rc_config_t ratectrl_config;
+ vpx_codec_err_t codec_status;
ratectrl_config.frame_width = frame_info->frame_width;
ratectrl_config.frame_height = frame_info->frame_height;
@@ -1755,7 +1756,10 @@ static vpx_codec_err_t ctrl_set_external_rate_control(vpx_codec_alg_priv_t *ctx,
ratectrl_config.frame_rate_num = oxcf->g_timebase.den;
ratectrl_config.frame_rate_den = oxcf->g_timebase.num;
- vp9_extrc_create(funcs, ratectrl_config, ext_ratectrl);
+ codec_status = vp9_extrc_create(funcs, ratectrl_config, ext_ratectrl);
+ if (codec_status != VPX_CODEC_OK) {
+ return codec_status;
+ }
}
return VPX_CODEC_OK;
}
diff --git a/vpx/vpx_encoder.h b/vpx/vpx_encoder.h
index 39b2aef62..da3609577 100644
--- a/vpx/vpx_encoder.h
+++ b/vpx/vpx_encoder.h
@@ -30,6 +30,7 @@ extern "C" {
#endif
#include "./vpx_codec.h"
+#include "./vpx_ext_ratectrl.h"
/*! Temporal Scalability: Maximum length of the sequence defining frame
* layer membership
@@ -57,7 +58,8 @@ extern "C" {
* fields to structures
*/
#define VPX_ENCODER_ABI_VERSION \
- (14 + VPX_CODEC_ABI_VERSION) /**<\hideinitializer*/
+ (14 + VPX_CODEC_ABI_VERSION + \
+ VPX_EXT_RATECTRL_ABI_VERSION) /**<\hideinitializer*/
/*! \brief Encoder capabilities bitfield
*
diff --git a/vpx/vpx_ext_ratectrl.h b/vpx/vpx_ext_ratectrl.h
index 5d5a7c92d..dc4d856a8 100644
--- a/vpx/vpx_ext_ratectrl.h
+++ b/vpx/vpx_ext_ratectrl.h
@@ -17,77 +17,238 @@ extern "C" {
#include "./vpx_integer.h"
-/*!\cond
- TODO(angiebird): document these structures and fields to clear doxygen
- warnings.*/
+/*!\brief Current ABI version number
+ *
+ * \internal
+ * If this file is altered in any way that changes the ABI, this value
+ * must be bumped. Examples include, but are not limited to, changing
+ * types, removing or reassigning enums, adding/removing/rearranging
+ * fields to structures.
+ */
+#define VPX_EXT_RATECTRL_ABI_VERSION (1)
+/*!\brief Abstract rate control model handler
+ *
+ * The encoder will receive the model handler from create_model() defined in
+ * vpx_rc_funcs_t.
+ */
typedef void *vpx_rc_model_t;
+/*!\brief Encode frame decision made by the external rate control model
+ *
+ * The encoder will receive the decision from the external rate control model
+ * through get_encodeframe_decision() defined in vpx_rc_funcs_t.
+ */
typedef struct vpx_rc_encodeframe_decision {
- int q_index;
+ int q_index; /**< Quantizer step index [0..255]*/
} vpx_rc_encodeframe_decision_t;
+/*!\brief Information for the frame to be encoded.
+ *
+ * The encoder will send the information to external rate control model through
+ * get_encodeframe_decision() defined in vpx_rc_funcs_t.
+ *
+ */
typedef struct vpx_rc_encodeframe_info {
+ /*!
+ * 0: Key frame
+ * 1: Inter frame
+ * 2: Alternate reference frame
+ * 3: Overlay frame
+ * 4: Golden frame
+ */
int frame_type;
- int show_index;
- int coding_index;
- int ref_frame_coding_indexes[3];
+ int show_index; /**< display index, starts from zero*/
+ int coding_index; /**< coding index, starts from zero*/
+ /*!
+ * index in group of picture, starts from zero.
+ */
+ int gop_index;
+ int ref_frame_coding_indexes[3]; /**< three reference frames' coding indices*/
+ /*!
+ * The validity of the three reference frames.
+ * 0: Invalid
+ * 1: Valid
+ */
int ref_frame_valid_list[3];
} vpx_rc_encodeframe_info_t;
+/*!\brief Frame coding result
+ *
+ * The encoder will send the result to the external rate control model through
+ * update_encodeframe_result() defined in vpx_rc_funcs_t.
+ */
typedef struct vpx_rc_encodeframe_result {
- int64_t sse;
- int64_t bit_count;
- int64_t pixel_count;
+ int64_t sse; /**< sum of squared error of the reconstructed frame */
+ int64_t bit_count; /**< number of bits spent on coding the frame*/
+ int64_t pixel_count; /**< number of pixels in YUV planes of the frame*/
} vpx_rc_encodeframe_result_t;
+/*!\brief Status returned by rate control callback functions.
+ */
typedef enum vpx_rc_status {
- vpx_rc_ok = 0,
- vpx_rc_error = 1,
+ VPX_RC_OK = 0,
+ VPX_RC_ERROR = 1,
} vpx_rc_status_t;
-// This is a mirror of vp9's FIRSTPASS_STATS
-// Only spatial_layer_id is omitted
+/*!\brief First pass frame stats
+ * This is a mirror of vp9's FIRSTPASS_STATS except that spatial_layer_id is
+ * omitted
+ */
typedef struct vpx_rc_frame_stats {
+ /*!
+ * Frame number in display order, if stats are for a single frame.
+ * No real meaning for a collection of frames.
+ */
double frame;
+ /*!
+ * Weight assigned to this frame (or total weight for the collection of
+ * frames) currently based on intra factor and brightness factor. This is used
+ * to distribute bits between easier and harder frames.
+ */
double weight;
+ /*!
+ * Intra prediction error.
+ */
double intra_error;
+ /*!
+ * Best of intra pred error and inter pred error using last frame as ref.
+ */
double coded_error;
+ /*!
+ * Best of intra pred error and inter pred error using golden frame as ref.
+ */
double sr_coded_error;
+ /*!
+ * Estimate the noise energy of the current frame.
+ */
double frame_noise_energy;
+ /*!
+ * Percentage of blocks with inter pred error < intra pred error.
+ */
double pcnt_inter;
+ /*!
+ * Percentage of blocks using (inter prediction and) non-zero motion vectors.
+ */
double pcnt_motion;
+ /*!
+ * Percentage of blocks where golden frame was better than last or intra:
+ * inter pred error using golden frame < inter pred error using last frame and
+ * inter pred error using golden frame < intra pred error
+ */
double pcnt_second_ref;
+ /*!
+ * Percentage of blocks where intra and inter prediction errors were very
+ * close.
+ */
double pcnt_neutral;
+ /*!
+ * Percentage of blocks that have intra error < inter error and inter error <
+ * LOW_I_THRESH
+ * - bit_depth 8: LOW_I_THRESH = 24000
+ * - bit_depth 10: LOW_I_THRESH = 24000 << 4
+ * - bit_depth 12: LOW_I_THRESH = 24000 << 8
+ */
double pcnt_intra_low;
+ /*!
+ * Percentage of blocks that have intra error < inter error and intra error <
+ * LOW_I_THRESH but inter error >= LOW_I_THRESH LOW_I_THRESH
+ * - bit_depth 8: LOW_I_THRESH = 24000
+ * - bit_depth 10: LOW_I_THRESH = 24000 << 4
+ * - bit_depth 12: LOW_I_THRESH = 24000 << 8
+ */
double pcnt_intra_high;
+ /*!
+ * Percentage of blocks that have almost no intra error residual
+ * (i.e. are in effect completely flat and untextured in the intra
+ * domain). In natural videos this is uncommon, but it is much more
+ * common in animations, graphics and screen content, so may be used
+ * as a signal to detect these types of content.
+ */
double intra_skip_pct;
+ /*!
+ * Percentage of blocks that have intra error < SMOOTH_INTRA_THRESH
+ * - bit_depth 8: SMOOTH_INTRA_THRESH = 4000
+ * - bit_depth 10: SMOOTH_INTRA_THRESH = 4000 << 4
+ * - bit_depth 12: SMOOTH_INTRA_THRESH = 4000 << 8
+ */
double intra_smooth_pct;
+ /*!
+ * Image mask rows top and bottom.
+ */
double inactive_zone_rows;
+ /*!
+ * Image mask columns at left and right edges.
+ */
double inactive_zone_cols;
+ /*!
+ * Mean of row motion vectors.
+ */
double MVr;
+ /*!
+ * Mean of absolute value of row motion vectors.
+ */
double mvr_abs;
+ /*!
+ * Mean of column motion vectors.
+ */
double MVc;
+ /*!
+ * Mean of absolute value of column motion vectors.
+ */
double mvc_abs;
+ /*!
+ * Variance of row motion vectors.
+ */
double MVrv;
+ /*!
+ * Variance of column motion vectors.
+ */
double MVcv;
+ /*!
+ * Value in range [-1,1] indicating fraction of row and column motion vectors
+ * that point inwards (negative MV value) or outwards (positive MV value).
+ * For example, value of 1 indicates, all row/column MVs are inwards.
+ */
double mv_in_out_count;
+ /*!
+ * Duration of the frame / collection of frames.
+ */
double duration;
+ /*!
+ * 1.0 if stats are for a single frame, or
+ * number of frames whose stats are accumulated.
+ */
double count;
} vpx_rc_frame_stats_t;
+/*!\brief Collection of first pass frame stats
+ */
typedef struct vpx_rc_firstpass_stats {
+ /*!
+ * Pointer to first pass frame stats.
+ * The pointed array of vpx_rc_frame_stats_t should have length equal to
+ * number of show frames in the video.
+ */
vpx_rc_frame_stats_t *frame_stats;
+ /*!
+ * Number of show frames in the video.
+ */
int num_frames;
} vpx_rc_firstpass_stats_t;
+/*!\brief Encode config sent to external rate control model
+ */
typedef struct vpx_rc_config {
- int frame_width;
- int frame_height;
- int show_frame_count;
+ int frame_width; /**< frame width */
+ int frame_height; /**< frame height */
+ int show_frame_count; /**< number of visible frames in the video */
+ /*!
+ * Target bitrate in kilobytes per second
+ */
int target_bitrate_kbps;
- int frame_rate_num;
- int frame_rate_den;
+ int frame_rate_num; /**< numerator of frame rate */
+ int frame_rate_den; /**< denominator of frame rate */
} vpx_rc_config_t;
/*!\brief Create an external rate control model callback prototype
@@ -152,19 +313,39 @@ typedef vpx_rc_status_t (*vpx_rc_update_encodeframe_result_cb_fn_t)(
typedef vpx_rc_status_t (*vpx_rc_delete_model_cb_fn_t)(
vpx_rc_model_t rate_ctrl_model);
+/*!\brief Callback function set for external rate control.
+ *
+ * The user can enable external rate control by registering
+ * a set of callback functions with the codec control flag
+ * VP9E_SET_EXTERNAL_RATE_CONTROL.
+ */
typedef struct vpx_rc_funcs {
+ /*!
+ * Create an external rate control model.
+ */
vpx_rc_create_model_cb_fn_t create_model;
+ /*!
+ * Send first pass stats to the external rate control model.
+ */
vpx_rc_send_firstpass_stats_cb_fn_t send_firstpass_stats;
+ /*!
+ * Get encodeframe decision from the external rate control model.
+ */
vpx_rc_get_encodeframe_decision_cb_fn_t get_encodeframe_decision;
+ /*!
+ * Update encodeframe result to the external rate control model.
+ */
vpx_rc_update_encodeframe_result_cb_fn_t update_encodeframe_result;
+ /*!
+ * Delete the external rate control model.
+ */
vpx_rc_delete_model_cb_fn_t delete_model;
+ /*!
+ * Private data for the external rate control model.
+ */
void *priv;
} vpx_rc_funcs_t;
-/*!\endcond
- TODO(angiebird): document these structures and fields to clear doxygen
- warnings.*/
-
#ifdef __cplusplus
} // extern "C"
#endif
diff --git a/vpx_dsp/arm/highbd_loopfilter_neon.c b/vpx_dsp/arm/highbd_loopfilter_neon.c
index 5530c6425..8d6e8acc4 100644
--- a/vpx_dsp/arm/highbd_loopfilter_neon.c
+++ b/vpx_dsp/arm/highbd_loopfilter_neon.c
@@ -661,6 +661,17 @@ void vpx_highbd_lpf_vertical_8_dual_neon(
vpx_highbd_lpf_vertical_8_neon(s + 8 * p, p, blimit1, limit1, thresh1, bd);
}
+// Quiet warnings of the form: 'vpx_dsp/arm/highbd_loopfilter_neon.c|675 col 67|
+// warning: 'oq1' may be used uninitialized in this function
+// [-Wmaybe-uninitialized]', for oq1-op1. Without reworking the code or adding
+// an additional branch this warning cannot be silenced otherwise. The
+// loopfilter is only called when needed for a block so these output pixels
+// will be set.
+#if defined(__GNUC__) && __GNUC__ >= 4 && !defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
+#endif
+
static void lpf_horizontal_16_kernel(uint16_t *s, int p,
const uint16x8_t blimit_vec,
const uint16x8_t limit_vec,
@@ -723,6 +734,10 @@ static void lpf_vertical_16_kernel(uint16_t *s, int p,
}
}
+#if defined(__GNUC__) && __GNUC__ >= 4 && !defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+
void vpx_highbd_lpf_horizontal_16_neon(uint16_t *s, int p,
const uint8_t *blimit,
const uint8_t *limit,
diff --git a/vpx_dsp/arm/loopfilter_neon.c b/vpx_dsp/arm/loopfilter_neon.c
index 7419cea02..c54e58823 100644
--- a/vpx_dsp/arm/loopfilter_neon.c
+++ b/vpx_dsp/arm/loopfilter_neon.c
@@ -975,6 +975,17 @@ FUN_LPF_16_KERNEL(_, 8) // lpf_16_kernel
FUN_LPF_16_KERNEL(_dual_, 16) // lpf_16_dual_kernel
#undef FUN_LPF_16_KERNEL
+// Quiet warnings of the form: 'vpx_dsp/arm/loopfilter_neon.c|981 col 42|
+// warning: 'oq1' may be used uninitialized in this function
+// [-Wmaybe-uninitialized]', for oq1-op1. Without reworking the code or adding
+// an additional branch this warning cannot be silenced otherwise. The
+// loopfilter is only called when needed for a block so these output pixels
+// will be set.
+#if defined(__GNUC__) && __GNUC__ >= 4 && !defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
+#endif
+
void vpx_lpf_horizontal_16_neon(uint8_t *s, int p, const uint8_t *blimit,
const uint8_t *limit, const uint8_t *thresh) {
uint8x8_t p7, p6, p5, p4, p3, p2, p1, p0, q0, q1, q2, q3, q4, q5, q6, q7, op6,
@@ -1090,3 +1101,7 @@ void vpx_lpf_vertical_16_dual_neon(uint8_t *s, int p, const uint8_t *blimit,
vget_high_u8(oq0), vget_high_u8(oq1));
}
}
+
+#if defined(__GNUC__) && __GNUC__ >= 4 && !defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
diff --git a/vpxenc.c b/vpxenc.c
index 5d7546eb2..5042e688c 100644
--- a/vpxenc.c
+++ b/vpxenc.c
@@ -1636,6 +1636,7 @@ int main(int argc, const char **argv_) {
int res = 0;
memset(&input, 0, sizeof(input));
+ memset(&raw, 0, sizeof(raw));
exec_name = argv_[0];
/* Setup default input stream settings */
@@ -1781,14 +1782,10 @@ int main(int argc, const char **argv_) {
FOREACH_STREAM(show_stream_config(stream, &global, &input));
if (pass == (global.pass ? global.pass - 1 : 0)) {
- if (input.file_type == FILE_TYPE_Y4M)
- /*The Y4M reader does its own allocation.
- Just initialize this here to avoid problems if we never read any
- frames.*/
- memset(&raw, 0, sizeof(raw));
- else
+ // The Y4M reader does its own allocation.
+ if (input.file_type != FILE_TYPE_Y4M) {
vpx_img_alloc(&raw, input.fmt, input.width, input.height, 32);
-
+ }
FOREACH_STREAM(stream->rate_hist = init_rate_histogram(
&stream->config.cfg, &global.framerate));
}
diff --git a/y4minput.c b/y4minput.c
index 007bd9971..68000768c 100644
--- a/y4minput.c
+++ b/y4minput.c
@@ -10,6 +10,7 @@
* Based on code from the OggTheora software codec source code,
* Copyright (C) 2002-2010 The Xiph.Org Foundation and contributors.
*/
+#include <assert.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
@@ -784,277 +785,294 @@ static void y4m_convert_null(y4m_input *_y4m, unsigned char *_dst,
(void)_aux;
}
-int y4m_input_open(y4m_input *_y4m, FILE *_fin, char *_skip, int _nskip,
- int only_420) {
+static const char TAG[] = "YUV4MPEG2";
+
+int y4m_input_open(y4m_input *y4m_ctx, FILE *file, char *skip_buffer,
+ int num_skip, int only_420) {
+ // File must start with |TAG|.
+ char tag_buffer[9]; // 9 == strlen(TAG)
char buffer[80] = { 0 };
int ret;
int i;
+ // Read as much as possible from |skip_buffer|, which were characters
+ // that were previously read from the file to do input-type detection.
+ assert(num_skip >= 0 && num_skip <= 8);
+ if (num_skip > 0) {
+ memcpy(tag_buffer, skip_buffer, num_skip);
+ }
+ // Start reading from the file now that the |skip_buffer| is depleted.
+ if (!file_read(tag_buffer + num_skip, 9 - num_skip, file)) {
+ return -1;
+ }
+ if (memcmp(TAG, tag_buffer, 9) != 0) {
+ fprintf(stderr, "Error parsing header: must start with %s\n", TAG);
+ return -1;
+ }
+ // Next character must be a space.
+ if (!file_read(buffer, 1, file) || buffer[0] != ' ') {
+ fprintf(stderr, "Error parsing header: space must follow %s\n", TAG);
+ return -1;
+ }
/*Read until newline, or 80 cols, whichever happens first.*/
for (i = 0; i < 79; i++) {
- if (_nskip > 0) {
- buffer[i] = *_skip++;
- _nskip--;
- } else {
- if (!file_read(buffer + i, 1, _fin)) return -1;
- }
+ if (!file_read(buffer + i, 1, file)) return -1;
if (buffer[i] == '\n') break;
}
/*We skipped too much header data.*/
- if (_nskip > 0) return -1;
if (i == 79) {
- fprintf(stderr, "Error parsing header; not a YUV2MPEG2 file?\n");
+ fprintf(stderr, "Error parsing header; not a YUV4MPEG2 file?\n");
return -1;
}
buffer[i] = '\0';
- if (memcmp(buffer, "YUV4MPEG", 8)) {
- fprintf(stderr, "Incomplete magic for YUV4MPEG file.\n");
- return -1;
- }
- if (buffer[8] != '2') {
- fprintf(stderr, "Incorrect YUV input file version; YUV4MPEG2 required.\n");
- }
- ret = y4m_parse_tags(_y4m, buffer + 5);
+ ret = y4m_parse_tags(y4m_ctx, buffer);
if (ret < 0) {
fprintf(stderr, "Error parsing YUV4MPEG2 header.\n");
return ret;
}
- if (_y4m->interlace == '?') {
+ if (y4m_ctx->interlace == '?') {
fprintf(stderr,
"Warning: Input video interlacing format unknown; "
"assuming progressive scan.\n");
- } else if (_y4m->interlace != 'p') {
+ } else if (y4m_ctx->interlace != 'p') {
fprintf(stderr,
"Input video is interlaced; "
"Only progressive scan handled.\n");
return -1;
}
- _y4m->vpx_fmt = VPX_IMG_FMT_I420;
- _y4m->bps = 12;
- _y4m->bit_depth = 8;
- if (strcmp(_y4m->chroma_type, "420") == 0 ||
- strcmp(_y4m->chroma_type, "420jpeg") == 0) {
- _y4m->src_c_dec_h = _y4m->dst_c_dec_h = _y4m->src_c_dec_v =
- _y4m->dst_c_dec_v = 2;
- _y4m->dst_buf_read_sz =
- _y4m->pic_w * _y4m->pic_h +
- 2 * ((_y4m->pic_w + 1) / 2) * ((_y4m->pic_h + 1) / 2);
+ y4m_ctx->vpx_fmt = VPX_IMG_FMT_I420;
+ y4m_ctx->bps = 12;
+ y4m_ctx->bit_depth = 8;
+ y4m_ctx->aux_buf = NULL;
+ y4m_ctx->dst_buf = NULL;
+ if (strcmp(y4m_ctx->chroma_type, "420") == 0 ||
+ strcmp(y4m_ctx->chroma_type, "420jpeg") == 0) {
+ y4m_ctx->src_c_dec_h = y4m_ctx->dst_c_dec_h = y4m_ctx->src_c_dec_v =
+ y4m_ctx->dst_c_dec_v = 2;
+ y4m_ctx->dst_buf_read_sz =
+ y4m_ctx->pic_w * y4m_ctx->pic_h +
+ 2 * ((y4m_ctx->pic_w + 1) / 2) * ((y4m_ctx->pic_h + 1) / 2);
/* Natively supported: no conversion required. */
- _y4m->aux_buf_sz = _y4m->aux_buf_read_sz = 0;
- _y4m->convert = y4m_convert_null;
- } else if (strcmp(_y4m->chroma_type, "420p10") == 0) {
- _y4m->src_c_dec_h = 2;
- _y4m->dst_c_dec_h = 2;
- _y4m->src_c_dec_v = 2;
- _y4m->dst_c_dec_v = 2;
- _y4m->dst_buf_read_sz =
- 2 * (_y4m->pic_w * _y4m->pic_h +
- 2 * ((_y4m->pic_w + 1) / 2) * ((_y4m->pic_h + 1) / 2));
+ y4m_ctx->aux_buf_sz = y4m_ctx->aux_buf_read_sz = 0;
+ y4m_ctx->convert = y4m_convert_null;
+ } else if (strcmp(y4m_ctx->chroma_type, "420p10") == 0) {
+ y4m_ctx->src_c_dec_h = 2;
+ y4m_ctx->dst_c_dec_h = 2;
+ y4m_ctx->src_c_dec_v = 2;
+ y4m_ctx->dst_c_dec_v = 2;
+ y4m_ctx->dst_buf_read_sz =
+ 2 * (y4m_ctx->pic_w * y4m_ctx->pic_h +
+ 2 * ((y4m_ctx->pic_w + 1) / 2) * ((y4m_ctx->pic_h + 1) / 2));
/* Natively supported: no conversion required. */
- _y4m->aux_buf_sz = _y4m->aux_buf_read_sz = 0;
- _y4m->convert = y4m_convert_null;
- _y4m->bit_depth = 10;
- _y4m->bps = 15;
- _y4m->vpx_fmt = VPX_IMG_FMT_I42016;
+ y4m_ctx->aux_buf_sz = y4m_ctx->aux_buf_read_sz = 0;
+ y4m_ctx->convert = y4m_convert_null;
+ y4m_ctx->bit_depth = 10;
+ y4m_ctx->bps = 15;
+ y4m_ctx->vpx_fmt = VPX_IMG_FMT_I42016;
if (only_420) {
fprintf(stderr, "Unsupported conversion from 420p10 to 420jpeg\n");
return -1;
}
- } else if (strcmp(_y4m->chroma_type, "420p12") == 0) {
- _y4m->src_c_dec_h = 2;
- _y4m->dst_c_dec_h = 2;
- _y4m->src_c_dec_v = 2;
- _y4m->dst_c_dec_v = 2;
- _y4m->dst_buf_read_sz =
- 2 * (_y4m->pic_w * _y4m->pic_h +
- 2 * ((_y4m->pic_w + 1) / 2) * ((_y4m->pic_h + 1) / 2));
+ } else if (strcmp(y4m_ctx->chroma_type, "420p12") == 0) {
+ y4m_ctx->src_c_dec_h = 2;
+ y4m_ctx->dst_c_dec_h = 2;
+ y4m_ctx->src_c_dec_v = 2;
+ y4m_ctx->dst_c_dec_v = 2;
+ y4m_ctx->dst_buf_read_sz =
+ 2 * (y4m_ctx->pic_w * y4m_ctx->pic_h +
+ 2 * ((y4m_ctx->pic_w + 1) / 2) * ((y4m_ctx->pic_h + 1) / 2));
/* Natively supported: no conversion required. */
- _y4m->aux_buf_sz = _y4m->aux_buf_read_sz = 0;
- _y4m->convert = y4m_convert_null;
- _y4m->bit_depth = 12;
- _y4m->bps = 18;
- _y4m->vpx_fmt = VPX_IMG_FMT_I42016;
+ y4m_ctx->aux_buf_sz = y4m_ctx->aux_buf_read_sz = 0;
+ y4m_ctx->convert = y4m_convert_null;
+ y4m_ctx->bit_depth = 12;
+ y4m_ctx->bps = 18;
+ y4m_ctx->vpx_fmt = VPX_IMG_FMT_I42016;
if (only_420) {
fprintf(stderr, "Unsupported conversion from 420p12 to 420jpeg\n");
return -1;
}
- } else if (strcmp(_y4m->chroma_type, "420mpeg2") == 0) {
- _y4m->src_c_dec_h = _y4m->dst_c_dec_h = _y4m->src_c_dec_v =
- _y4m->dst_c_dec_v = 2;
- _y4m->dst_buf_read_sz = _y4m->pic_w * _y4m->pic_h;
+ } else if (strcmp(y4m_ctx->chroma_type, "420mpeg2") == 0) {
+ y4m_ctx->src_c_dec_h = y4m_ctx->dst_c_dec_h = y4m_ctx->src_c_dec_v =
+ y4m_ctx->dst_c_dec_v = 2;
+ y4m_ctx->dst_buf_read_sz = y4m_ctx->pic_w * y4m_ctx->pic_h;
/*Chroma filter required: read into the aux buf first.*/
- _y4m->aux_buf_sz = _y4m->aux_buf_read_sz =
- 2 * ((_y4m->pic_w + 1) / 2) * ((_y4m->pic_h + 1) / 2);
- _y4m->convert = y4m_convert_42xmpeg2_42xjpeg;
- } else if (strcmp(_y4m->chroma_type, "420paldv") == 0) {
- _y4m->src_c_dec_h = _y4m->dst_c_dec_h = _y4m->src_c_dec_v =
- _y4m->dst_c_dec_v = 2;
- _y4m->dst_buf_read_sz = _y4m->pic_w * _y4m->pic_h;
+ y4m_ctx->aux_buf_sz = y4m_ctx->aux_buf_read_sz =
+ 2 * ((y4m_ctx->pic_w + 1) / 2) * ((y4m_ctx->pic_h + 1) / 2);
+ y4m_ctx->convert = y4m_convert_42xmpeg2_42xjpeg;
+ } else if (strcmp(y4m_ctx->chroma_type, "420paldv") == 0) {
+ y4m_ctx->src_c_dec_h = y4m_ctx->dst_c_dec_h = y4m_ctx->src_c_dec_v =
+ y4m_ctx->dst_c_dec_v = 2;
+ y4m_ctx->dst_buf_read_sz = y4m_ctx->pic_w * y4m_ctx->pic_h;
/*Chroma filter required: read into the aux buf first.
We need to make two filter passes, so we need some extra space in the
aux buffer.*/
- _y4m->aux_buf_sz = 3 * ((_y4m->pic_w + 1) / 2) * ((_y4m->pic_h + 1) / 2);
- _y4m->aux_buf_read_sz =
- 2 * ((_y4m->pic_w + 1) / 2) * ((_y4m->pic_h + 1) / 2);
- _y4m->convert = y4m_convert_42xpaldv_42xjpeg;
- } else if (strcmp(_y4m->chroma_type, "422jpeg") == 0) {
- _y4m->src_c_dec_h = _y4m->dst_c_dec_h = 2;
- _y4m->src_c_dec_v = 1;
- _y4m->dst_c_dec_v = 2;
- _y4m->dst_buf_read_sz = _y4m->pic_w * _y4m->pic_h;
+ y4m_ctx->aux_buf_sz =
+ 3 * ((y4m_ctx->pic_w + 1) / 2) * ((y4m_ctx->pic_h + 1) / 2);
+ y4m_ctx->aux_buf_read_sz =
+ 2 * ((y4m_ctx->pic_w + 1) / 2) * ((y4m_ctx->pic_h + 1) / 2);
+ y4m_ctx->convert = y4m_convert_42xpaldv_42xjpeg;
+ } else if (strcmp(y4m_ctx->chroma_type, "422jpeg") == 0) {
+ y4m_ctx->src_c_dec_h = y4m_ctx->dst_c_dec_h = 2;
+ y4m_ctx->src_c_dec_v = 1;
+ y4m_ctx->dst_c_dec_v = 2;
+ y4m_ctx->dst_buf_read_sz = y4m_ctx->pic_w * y4m_ctx->pic_h;
/*Chroma filter required: read into the aux buf first.*/
- _y4m->aux_buf_sz = _y4m->aux_buf_read_sz =
- 2 * ((_y4m->pic_w + 1) / 2) * _y4m->pic_h;
- _y4m->convert = y4m_convert_422jpeg_420jpeg;
- } else if (strcmp(_y4m->chroma_type, "422") == 0) {
- _y4m->src_c_dec_h = 2;
- _y4m->src_c_dec_v = 1;
+ y4m_ctx->aux_buf_sz = y4m_ctx->aux_buf_read_sz =
+ 2 * ((y4m_ctx->pic_w + 1) / 2) * y4m_ctx->pic_h;
+ y4m_ctx->convert = y4m_convert_422jpeg_420jpeg;
+ } else if (strcmp(y4m_ctx->chroma_type, "422") == 0) {
+ y4m_ctx->src_c_dec_h = 2;
+ y4m_ctx->src_c_dec_v = 1;
if (only_420) {
- _y4m->dst_c_dec_h = 2;
- _y4m->dst_c_dec_v = 2;
- _y4m->dst_buf_read_sz = _y4m->pic_w * _y4m->pic_h;
+ y4m_ctx->dst_c_dec_h = 2;
+ y4m_ctx->dst_c_dec_v = 2;
+ y4m_ctx->dst_buf_read_sz = y4m_ctx->pic_w * y4m_ctx->pic_h;
/*Chroma filter required: read into the aux buf first.
We need to make two filter passes, so we need some extra space in the
aux buffer.*/
- _y4m->aux_buf_read_sz = 2 * ((_y4m->pic_w + 1) / 2) * _y4m->pic_h;
- _y4m->aux_buf_sz =
- _y4m->aux_buf_read_sz + ((_y4m->pic_w + 1) / 2) * _y4m->pic_h;
- _y4m->convert = y4m_convert_422_420jpeg;
+ y4m_ctx->aux_buf_read_sz =
+ 2 * ((y4m_ctx->pic_w + 1) / 2) * y4m_ctx->pic_h;
+ y4m_ctx->aux_buf_sz = y4m_ctx->aux_buf_read_sz +
+ ((y4m_ctx->pic_w + 1) / 2) * y4m_ctx->pic_h;
+ y4m_ctx->convert = y4m_convert_422_420jpeg;
} else {
- _y4m->vpx_fmt = VPX_IMG_FMT_I422;
- _y4m->bps = 16;
- _y4m->dst_c_dec_h = _y4m->src_c_dec_h;
- _y4m->dst_c_dec_v = _y4m->src_c_dec_v;
- _y4m->dst_buf_read_sz =
- _y4m->pic_w * _y4m->pic_h + 2 * ((_y4m->pic_w + 1) / 2) * _y4m->pic_h;
+ y4m_ctx->vpx_fmt = VPX_IMG_FMT_I422;
+ y4m_ctx->bps = 16;
+ y4m_ctx->dst_c_dec_h = y4m_ctx->src_c_dec_h;
+ y4m_ctx->dst_c_dec_v = y4m_ctx->src_c_dec_v;
+ y4m_ctx->dst_buf_read_sz =
+ y4m_ctx->pic_w * y4m_ctx->pic_h +
+ 2 * ((y4m_ctx->pic_w + 1) / 2) * y4m_ctx->pic_h;
/*Natively supported: no conversion required.*/
- _y4m->aux_buf_sz = _y4m->aux_buf_read_sz = 0;
- _y4m->convert = y4m_convert_null;
+ y4m_ctx->aux_buf_sz = y4m_ctx->aux_buf_read_sz = 0;
+ y4m_ctx->convert = y4m_convert_null;
}
- } else if (strcmp(_y4m->chroma_type, "422p10") == 0) {
- _y4m->src_c_dec_h = 2;
- _y4m->src_c_dec_v = 1;
- _y4m->vpx_fmt = VPX_IMG_FMT_I42216;
- _y4m->bps = 20;
- _y4m->bit_depth = 10;
- _y4m->dst_c_dec_h = _y4m->src_c_dec_h;
- _y4m->dst_c_dec_v = _y4m->src_c_dec_v;
- _y4m->dst_buf_read_sz = 2 * (_y4m->pic_w * _y4m->pic_h +
- 2 * ((_y4m->pic_w + 1) / 2) * _y4m->pic_h);
- _y4m->aux_buf_sz = _y4m->aux_buf_read_sz = 0;
- _y4m->convert = y4m_convert_null;
+ } else if (strcmp(y4m_ctx->chroma_type, "422p10") == 0) {
+ y4m_ctx->src_c_dec_h = 2;
+ y4m_ctx->src_c_dec_v = 1;
+ y4m_ctx->vpx_fmt = VPX_IMG_FMT_I42216;
+ y4m_ctx->bps = 20;
+ y4m_ctx->bit_depth = 10;
+ y4m_ctx->dst_c_dec_h = y4m_ctx->src_c_dec_h;
+ y4m_ctx->dst_c_dec_v = y4m_ctx->src_c_dec_v;
+ y4m_ctx->dst_buf_read_sz =
+ 2 * (y4m_ctx->pic_w * y4m_ctx->pic_h +
+ 2 * ((y4m_ctx->pic_w + 1) / 2) * y4m_ctx->pic_h);
+ y4m_ctx->aux_buf_sz = y4m_ctx->aux_buf_read_sz = 0;
+ y4m_ctx->convert = y4m_convert_null;
if (only_420) {
fprintf(stderr, "Unsupported conversion from 422p10 to 420jpeg\n");
return -1;
}
- } else if (strcmp(_y4m->chroma_type, "422p12") == 0) {
- _y4m->src_c_dec_h = 2;
- _y4m->src_c_dec_v = 1;
- _y4m->vpx_fmt = VPX_IMG_FMT_I42216;
- _y4m->bps = 24;
- _y4m->bit_depth = 12;
- _y4m->dst_c_dec_h = _y4m->src_c_dec_h;
- _y4m->dst_c_dec_v = _y4m->src_c_dec_v;
- _y4m->dst_buf_read_sz = 2 * (_y4m->pic_w * _y4m->pic_h +
- 2 * ((_y4m->pic_w + 1) / 2) * _y4m->pic_h);
- _y4m->aux_buf_sz = _y4m->aux_buf_read_sz = 0;
- _y4m->convert = y4m_convert_null;
+ } else if (strcmp(y4m_ctx->chroma_type, "422p12") == 0) {
+ y4m_ctx->src_c_dec_h = 2;
+ y4m_ctx->src_c_dec_v = 1;
+ y4m_ctx->vpx_fmt = VPX_IMG_FMT_I42216;
+ y4m_ctx->bps = 24;
+ y4m_ctx->bit_depth = 12;
+ y4m_ctx->dst_c_dec_h = y4m_ctx->src_c_dec_h;
+ y4m_ctx->dst_c_dec_v = y4m_ctx->src_c_dec_v;
+ y4m_ctx->dst_buf_read_sz =
+ 2 * (y4m_ctx->pic_w * y4m_ctx->pic_h +
+ 2 * ((y4m_ctx->pic_w + 1) / 2) * y4m_ctx->pic_h);
+ y4m_ctx->aux_buf_sz = y4m_ctx->aux_buf_read_sz = 0;
+ y4m_ctx->convert = y4m_convert_null;
if (only_420) {
fprintf(stderr, "Unsupported conversion from 422p12 to 420jpeg\n");
return -1;
}
- } else if (strcmp(_y4m->chroma_type, "411") == 0) {
- _y4m->src_c_dec_h = 4;
- _y4m->dst_c_dec_h = 2;
- _y4m->src_c_dec_v = 1;
- _y4m->dst_c_dec_v = 2;
- _y4m->dst_buf_read_sz = _y4m->pic_w * _y4m->pic_h;
+ } else if (strcmp(y4m_ctx->chroma_type, "411") == 0) {
+ y4m_ctx->src_c_dec_h = 4;
+ y4m_ctx->dst_c_dec_h = 2;
+ y4m_ctx->src_c_dec_v = 1;
+ y4m_ctx->dst_c_dec_v = 2;
+ y4m_ctx->dst_buf_read_sz = y4m_ctx->pic_w * y4m_ctx->pic_h;
/*Chroma filter required: read into the aux buf first.
We need to make two filter passes, so we need some extra space in the
aux buffer.*/
- _y4m->aux_buf_read_sz = 2 * ((_y4m->pic_w + 3) / 4) * _y4m->pic_h;
- _y4m->aux_buf_sz =
- _y4m->aux_buf_read_sz + ((_y4m->pic_w + 1) / 2) * _y4m->pic_h;
- _y4m->convert = y4m_convert_411_420jpeg;
+ y4m_ctx->aux_buf_read_sz = 2 * ((y4m_ctx->pic_w + 3) / 4) * y4m_ctx->pic_h;
+ y4m_ctx->aux_buf_sz =
+ y4m_ctx->aux_buf_read_sz + ((y4m_ctx->pic_w + 1) / 2) * y4m_ctx->pic_h;
+ y4m_ctx->convert = y4m_convert_411_420jpeg;
fprintf(stderr, "Unsupported conversion from yuv 411\n");
return -1;
- } else if (strcmp(_y4m->chroma_type, "444") == 0) {
- _y4m->src_c_dec_h = 1;
- _y4m->src_c_dec_v = 1;
+ } else if (strcmp(y4m_ctx->chroma_type, "444") == 0) {
+ y4m_ctx->src_c_dec_h = 1;
+ y4m_ctx->src_c_dec_v = 1;
if (only_420) {
- _y4m->dst_c_dec_h = 2;
- _y4m->dst_c_dec_v = 2;
- _y4m->dst_buf_read_sz = _y4m->pic_w * _y4m->pic_h;
+ y4m_ctx->dst_c_dec_h = 2;
+ y4m_ctx->dst_c_dec_v = 2;
+ y4m_ctx->dst_buf_read_sz = y4m_ctx->pic_w * y4m_ctx->pic_h;
/*Chroma filter required: read into the aux buf first.
We need to make two filter passes, so we need some extra space in the
aux buffer.*/
- _y4m->aux_buf_read_sz = 2 * _y4m->pic_w * _y4m->pic_h;
- _y4m->aux_buf_sz =
- _y4m->aux_buf_read_sz + ((_y4m->pic_w + 1) / 2) * _y4m->pic_h;
- _y4m->convert = y4m_convert_444_420jpeg;
+ y4m_ctx->aux_buf_read_sz = 2 * y4m_ctx->pic_w * y4m_ctx->pic_h;
+ y4m_ctx->aux_buf_sz = y4m_ctx->aux_buf_read_sz +
+ ((y4m_ctx->pic_w + 1) / 2) * y4m_ctx->pic_h;
+ y4m_ctx->convert = y4m_convert_444_420jpeg;
} else {
- _y4m->vpx_fmt = VPX_IMG_FMT_I444;
- _y4m->bps = 24;
- _y4m->dst_c_dec_h = _y4m->src_c_dec_h;
- _y4m->dst_c_dec_v = _y4m->src_c_dec_v;
- _y4m->dst_buf_read_sz = 3 * _y4m->pic_w * _y4m->pic_h;
+ y4m_ctx->vpx_fmt = VPX_IMG_FMT_I444;
+ y4m_ctx->bps = 24;
+ y4m_ctx->dst_c_dec_h = y4m_ctx->src_c_dec_h;
+ y4m_ctx->dst_c_dec_v = y4m_ctx->src_c_dec_v;
+ y4m_ctx->dst_buf_read_sz = 3 * y4m_ctx->pic_w * y4m_ctx->pic_h;
/*Natively supported: no conversion required.*/
- _y4m->aux_buf_sz = _y4m->aux_buf_read_sz = 0;
- _y4m->convert = y4m_convert_null;
+ y4m_ctx->aux_buf_sz = y4m_ctx->aux_buf_read_sz = 0;
+ y4m_ctx->convert = y4m_convert_null;
}
- } else if (strcmp(_y4m->chroma_type, "444p10") == 0) {
- _y4m->src_c_dec_h = 1;
- _y4m->src_c_dec_v = 1;
- _y4m->vpx_fmt = VPX_IMG_FMT_I44416;
- _y4m->bps = 30;
- _y4m->bit_depth = 10;
- _y4m->dst_c_dec_h = _y4m->src_c_dec_h;
- _y4m->dst_c_dec_v = _y4m->src_c_dec_v;
- _y4m->dst_buf_read_sz = 2 * 3 * _y4m->pic_w * _y4m->pic_h;
- _y4m->aux_buf_sz = _y4m->aux_buf_read_sz = 0;
- _y4m->convert = y4m_convert_null;
+ } else if (strcmp(y4m_ctx->chroma_type, "444p10") == 0) {
+ y4m_ctx->src_c_dec_h = 1;
+ y4m_ctx->src_c_dec_v = 1;
+ y4m_ctx->vpx_fmt = VPX_IMG_FMT_I44416;
+ y4m_ctx->bps = 30;
+ y4m_ctx->bit_depth = 10;
+ y4m_ctx->dst_c_dec_h = y4m_ctx->src_c_dec_h;
+ y4m_ctx->dst_c_dec_v = y4m_ctx->src_c_dec_v;
+ y4m_ctx->dst_buf_read_sz = 2 * 3 * y4m_ctx->pic_w * y4m_ctx->pic_h;
+ y4m_ctx->aux_buf_sz = y4m_ctx->aux_buf_read_sz = 0;
+ y4m_ctx->convert = y4m_convert_null;
if (only_420) {
fprintf(stderr, "Unsupported conversion from 444p10 to 420jpeg\n");
return -1;
}
- } else if (strcmp(_y4m->chroma_type, "444p12") == 0) {
- _y4m->src_c_dec_h = 1;
- _y4m->src_c_dec_v = 1;
- _y4m->vpx_fmt = VPX_IMG_FMT_I44416;
- _y4m->bps = 36;
- _y4m->bit_depth = 12;
- _y4m->dst_c_dec_h = _y4m->src_c_dec_h;
- _y4m->dst_c_dec_v = _y4m->src_c_dec_v;
- _y4m->dst_buf_read_sz = 2 * 3 * _y4m->pic_w * _y4m->pic_h;
- _y4m->aux_buf_sz = _y4m->aux_buf_read_sz = 0;
- _y4m->convert = y4m_convert_null;
+ } else if (strcmp(y4m_ctx->chroma_type, "444p12") == 0) {
+ y4m_ctx->src_c_dec_h = 1;
+ y4m_ctx->src_c_dec_v = 1;
+ y4m_ctx->vpx_fmt = VPX_IMG_FMT_I44416;
+ y4m_ctx->bps = 36;
+ y4m_ctx->bit_depth = 12;
+ y4m_ctx->dst_c_dec_h = y4m_ctx->src_c_dec_h;
+ y4m_ctx->dst_c_dec_v = y4m_ctx->src_c_dec_v;
+ y4m_ctx->dst_buf_read_sz = 2 * 3 * y4m_ctx->pic_w * y4m_ctx->pic_h;
+ y4m_ctx->aux_buf_sz = y4m_ctx->aux_buf_read_sz = 0;
+ y4m_ctx->convert = y4m_convert_null;
if (only_420) {
fprintf(stderr, "Unsupported conversion from 444p12 to 420jpeg\n");
return -1;
}
- } else if (strcmp(_y4m->chroma_type, "mono") == 0) {
- _y4m->src_c_dec_h = _y4m->src_c_dec_v = 0;
- _y4m->dst_c_dec_h = _y4m->dst_c_dec_v = 2;
- _y4m->dst_buf_read_sz = _y4m->pic_w * _y4m->pic_h;
+ } else if (strcmp(y4m_ctx->chroma_type, "mono") == 0) {
+ y4m_ctx->src_c_dec_h = y4m_ctx->src_c_dec_v = 0;
+ y4m_ctx->dst_c_dec_h = y4m_ctx->dst_c_dec_v = 2;
+ y4m_ctx->dst_buf_read_sz = y4m_ctx->pic_w * y4m_ctx->pic_h;
/*No extra space required, but we need to clear the chroma planes.*/
- _y4m->aux_buf_sz = _y4m->aux_buf_read_sz = 0;
- _y4m->convert = y4m_convert_mono_420jpeg;
+ y4m_ctx->aux_buf_sz = y4m_ctx->aux_buf_read_sz = 0;
+ y4m_ctx->convert = y4m_convert_mono_420jpeg;
} else {
- fprintf(stderr, "Unknown chroma sampling type: %s\n", _y4m->chroma_type);
+ fprintf(stderr, "Unknown chroma sampling type: %s\n", y4m_ctx->chroma_type);
return -1;
}
/*The size of the final frame buffers is always computed from the
destination chroma decimation type.*/
- _y4m->dst_buf_sz =
- _y4m->pic_w * _y4m->pic_h +
- 2 * ((_y4m->pic_w + _y4m->dst_c_dec_h - 1) / _y4m->dst_c_dec_h) *
- ((_y4m->pic_h + _y4m->dst_c_dec_v - 1) / _y4m->dst_c_dec_v);
- if (_y4m->bit_depth == 8)
- _y4m->dst_buf = (unsigned char *)malloc(_y4m->dst_buf_sz);
+ y4m_ctx->dst_buf_sz =
+ y4m_ctx->pic_w * y4m_ctx->pic_h +
+ 2 * ((y4m_ctx->pic_w + y4m_ctx->dst_c_dec_h - 1) / y4m_ctx->dst_c_dec_h) *
+ ((y4m_ctx->pic_h + y4m_ctx->dst_c_dec_v - 1) / y4m_ctx->dst_c_dec_v);
+ if (y4m_ctx->bit_depth == 8)
+ y4m_ctx->dst_buf = (unsigned char *)malloc(y4m_ctx->dst_buf_sz);
else
- _y4m->dst_buf = (unsigned char *)malloc(2 * _y4m->dst_buf_sz);
+ y4m_ctx->dst_buf = (unsigned char *)malloc(2 * y4m_ctx->dst_buf_sz);
- if (_y4m->aux_buf_sz > 0)
- _y4m->aux_buf = (unsigned char *)malloc(_y4m->aux_buf_sz);
+ if (y4m_ctx->aux_buf_sz > 0)
+ y4m_ctx->aux_buf = (unsigned char *)malloc(y4m_ctx->aux_buf_sz);
return 0;
}
diff --git a/y4minput.h b/y4minput.h
index a4a8b18dc..573750d74 100644
--- a/y4minput.h
+++ b/y4minput.h
@@ -56,8 +56,16 @@ struct y4m_input {
unsigned int bit_depth;
};
-int y4m_input_open(y4m_input *_y4m, FILE *_fin, char *_skip, int _nskip,
- int only_420);
+/**
+ * Open the input file, treating it as Y4M. |y4m_ctx| is filled in after
+ * reading it. The |skip_buffer| indicates bytes that were previously read
+ * from |file|, to do input-type detection; this buffer will be read before
+ * the |file| is read. It is of size |num_skip|, which *must* be 8 or less.
+ *
+ * Returns 0 on success, -1 on failure.
+ */
+int y4m_input_open(y4m_input *y4m_ctx, FILE *file, char *skip_buffer,
+ int num_skip, int only_420);
void y4m_input_close(y4m_input *_y4m);
int y4m_input_fetch_frame(y4m_input *_y4m, FILE *_fin, vpx_image_t *img);