Commit 5820c5d6 authored by Deb Mukherjee's avatar Deb Mukherjee

Adds support for reading and writing 10/12-bit y4m

The y4m extension used is the same as the one used in ffmpeg/x264.
The patch is adapted from the highbitdepth branch.

Also adds unit tests for y4m header parsing and md5 check
of the raw frame data, as well as y4m writing.

[build fix for Mac/VS by not using tuples with strings]

Change-Id: I40897ee37d289e4b6cea6fedc67047d692b8cb46
parent 3643544f
...@@ -28,10 +28,11 @@ class MD5 { ...@@ -28,10 +28,11 @@ class MD5 {
// plane, we never want to round down and thus skip a pixel so if // plane, we never want to round down and thus skip a pixel so if
// we are shifting by 1 (chroma_shift) we add 1 before doing the shift. // we are shifting by 1 (chroma_shift) we add 1 before doing the shift.
// This works only for chroma_shift of 0 and 1. // This works only for chroma_shift of 0 and 1.
const int bytes_per_sample = (img->fmt & VPX_IMG_FMT_HIGH) ? 2 : 1;
const int h = plane ? (img->d_h + img->y_chroma_shift) >> const int h = plane ? (img->d_h + img->y_chroma_shift) >>
img->y_chroma_shift : img->d_h; img->y_chroma_shift : img->d_h;
const int w = plane ? (img->d_w + img->x_chroma_shift) >> const int w = (plane ? (img->d_w + img->x_chroma_shift) >>
img->x_chroma_shift : img->d_w; img->x_chroma_shift : img->d_w) * bytes_per_sample;
for (int y = 0; y < h; ++y) { for (int y = 0; y < h; ++y) {
MD5Update(&md5_, buf, w); MD5Update(&md5_, buf, w);
......
...@@ -6,6 +6,15 @@ d78e2fceba5ac942246503ec8366f879c4775ca5 invalid-vp90-02.webm ...@@ -6,6 +6,15 @@ d78e2fceba5ac942246503ec8366f879c4775ca5 invalid-vp90-02.webm
2dadee5306245fa5eeb0f99652d0e17afbcba96d invalid-vp90-02.webm.res 2dadee5306245fa5eeb0f99652d0e17afbcba96d invalid-vp90-02.webm.res
df1a1453feb3c00d7d89746c7003b4163523bff3 invalid-vp90-03.webm df1a1453feb3c00d7d89746c7003b4163523bff3 invalid-vp90-03.webm
8fe6fd82bf537340f586f97a7ae31fb37ccda302 invalid-vp90-03.webm.res 8fe6fd82bf537340f586f97a7ae31fb37ccda302 invalid-vp90-03.webm.res
a432f96ff0a787268e2f94a8092ab161a18d1b06 park_joy_90p_10_420.y4m
0b194cc312c3a2e84d156a221b0a5eb615dfddc5 park_joy_90p_10_422.y4m
ff0e0a21dc2adc95b8c1b37902713700655ced17 park_joy_90p_10_444.y4m
614c32ae1eca391e867c70d19974f0d62664dd99 park_joy_90p_12_420.y4m
c92825f1ea25c5c37855083a69faac6ac4641a9e park_joy_90p_12_422.y4m
b592189b885b6cc85db55cc98512a197d73d3b34 park_joy_90p_12_444.y4m
4e0eb61e76f0684188d9bc9f3ce61f6b6b77bb2c park_joy_90p_8_420.y4m
7a193ff7dfeb96ba5f82b2afd7afa9e1fe83d947 park_joy_90p_8_422.y4m
bdb7856e6bc93599bdda05c2e773a9f22b6c6d03 park_joy_90p_8_444.y4m
b1f1c3ec79114b9a0651af24ce634afb44a9a419 rush_hour_444.y4m b1f1c3ec79114b9a0651af24ce634afb44a9a419 rush_hour_444.y4m
5184c46ddca8b1fadd16742e8500115bc8f749da vp80-00-comprehensive-001.ivf 5184c46ddca8b1fadd16742e8500115bc8f749da vp80-00-comprehensive-001.ivf
65bf1bbbced81b97bd030f376d1b7f61a224793f vp80-00-comprehensive-002.ivf 65bf1bbbced81b97bd030f376d1b7f61a224793f vp80-00-comprehensive-002.ivf
......
...@@ -15,7 +15,7 @@ LIBVPX_TEST_SRCS-yes += video_source.h ...@@ -15,7 +15,7 @@ LIBVPX_TEST_SRCS-yes += video_source.h
## ##
## Black box tests only use the public API. ## Black box tests only use the public API.
## ##
LIBVPX_TEST_SRCS-$(CONFIG_DECODERS) += ../md5_utils.h ../md5_utils.c LIBVPX_TEST_SRCS-yes += ../md5_utils.h ../md5_utils.c
LIBVPX_TEST_SRCS-$(CONFIG_DECODERS) += ivf_video_source.h LIBVPX_TEST_SRCS-$(CONFIG_DECODERS) += ivf_video_source.h
LIBVPX_TEST_SRCS-$(CONFIG_ENCODERS) += ../y4minput.h ../y4minput.c LIBVPX_TEST_SRCS-$(CONFIG_ENCODERS) += ../y4minput.h ../y4minput.c
LIBVPX_TEST_SRCS-$(CONFIG_ENCODERS) += aq_segment_test.cc LIBVPX_TEST_SRCS-$(CONFIG_ENCODERS) += aq_segment_test.cc
...@@ -42,6 +42,9 @@ LIBVPX_TEST_SRCS-yes += decode_test_driver.h ...@@ -42,6 +42,9 @@ LIBVPX_TEST_SRCS-yes += decode_test_driver.h
LIBVPX_TEST_SRCS-yes += encode_test_driver.cc LIBVPX_TEST_SRCS-yes += encode_test_driver.cc
LIBVPX_TEST_SRCS-yes += encode_test_driver.h LIBVPX_TEST_SRCS-yes += encode_test_driver.h
## Y4m parsing.
LIBVPX_TEST_SRCS-$(CONFIG_ENCODERS) += y4m_test.cc ../y4menc.c ../y4menc.h
## WebM Parsing ## WebM Parsing
ifeq ($(CONFIG_WEBM_IO), yes) ifeq ($(CONFIG_WEBM_IO), yes)
LIBWEBM_PARSER_SRCS += ../third_party/libwebm/mkvparser.cpp LIBWEBM_PARSER_SRCS += ../third_party/libwebm/mkvparser.cpp
...@@ -134,6 +137,17 @@ endif # CONFIG_SHARED ...@@ -134,6 +137,17 @@ endif # CONFIG_SHARED
## ##
LIBVPX_TEST_DATA-$(CONFIG_ENCODERS) += hantro_collage_w352h288.yuv LIBVPX_TEST_DATA-$(CONFIG_ENCODERS) += hantro_collage_w352h288.yuv
LIBVPX_TEST_DATA-$(CONFIG_ENCODERS) += hantro_odd.yuv LIBVPX_TEST_DATA-$(CONFIG_ENCODERS) += hantro_odd.yuv
LIBVPX_TEST_DATA-$(CONFIG_ENCODERS) += park_joy_90p_10_420.y4m
LIBVPX_TEST_DATA-$(CONFIG_ENCODERS) += park_joy_90p_10_422.y4m
LIBVPX_TEST_DATA-$(CONFIG_ENCODERS) += park_joy_90p_10_444.y4m
LIBVPX_TEST_DATA-$(CONFIG_ENCODERS) += park_joy_90p_12_420.y4m
LIBVPX_TEST_DATA-$(CONFIG_ENCODERS) += park_joy_90p_12_422.y4m
LIBVPX_TEST_DATA-$(CONFIG_ENCODERS) += park_joy_90p_12_444.y4m
LIBVPX_TEST_DATA-$(CONFIG_ENCODERS) += park_joy_90p_8_420.y4m
LIBVPX_TEST_DATA-$(CONFIG_ENCODERS) += park_joy_90p_8_422.y4m
LIBVPX_TEST_DATA-$(CONFIG_ENCODERS) += park_joy_90p_8_444.y4m
LIBVPX_TEST_DATA-$(CONFIG_VP9_ENCODER) += rush_hour_444.y4m LIBVPX_TEST_DATA-$(CONFIG_VP9_ENCODER) += rush_hour_444.y4m
LIBVPX_TEST_DATA-$(CONFIG_VP9_ENCODER) += screendata.y4m LIBVPX_TEST_DATA-$(CONFIG_VP9_ENCODER) += screendata.y4m
......
...@@ -50,6 +50,15 @@ static FILE *OpenTestDataFile(const std::string& file_name) { ...@@ -50,6 +50,15 @@ static FILE *OpenTestDataFile(const std::string& file_name) {
return fopen(path_to_source.c_str(), "rb"); return fopen(path_to_source.c_str(), "rb");
} }
static FILE *OpenTestOutFile(const std::string& file_name) {
const std::string path_to_source = GetDataPath() + "/" + file_name;
return fopen(path_to_source.c_str(), "wb");
}
static FILE *OpenTempOutFile() {
return tmpfile();
}
// Abstract base class for test video sources, which provide a stream of // Abstract base class for test video sources, which provide a stream of
// vpx_image_t images with associated timestamps and duration. // vpx_image_t images with associated timestamps and duration.
class VideoSource { class VideoSource {
......
/*
* Copyright (c) 2012 The WebM project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include <string>
#include "test/md5_helper.h"
#include "test/util.h"
#include "test/y4m_video_source.h"
#include "third_party/googletest/src/include/gtest/gtest.h"
#include "./vpx_config.h"
#include "./y4menc.h"
namespace {
using std::string;
static const unsigned int kWidth = 160;
static const unsigned int kHeight = 90;
static const unsigned int kFrames = 10;
typedef struct {
const char *filename;
unsigned int bit_depth;
vpx_img_fmt format;
const char *md5raw;
} test_entry_type;
const test_entry_type kY4mTestVectors[] = {
{"park_joy_90p_8_420.y4m", 8, VPX_IMG_FMT_I420,
"e5406275b9fc6bb3436c31d4a05c1cab"},
{"park_joy_90p_8_422.y4m", 8, VPX_IMG_FMT_I422,
"284a47a47133b12884ec3a14e959a0b6"},
{"park_joy_90p_8_444.y4m", 8, VPX_IMG_FMT_I444,
"90517ff33843d85de712fd4fe60dbed0"},
{"park_joy_90p_10_420.y4m", 10, VPX_IMG_FMT_I42016,
"63f21f9f717d8b8631bd2288ee87137b"},
{"park_joy_90p_10_422.y4m", 10, VPX_IMG_FMT_I42216,
"48ab51fb540aed07f7ff5af130c9b605"},
{"park_joy_90p_10_444.y4m", 10, VPX_IMG_FMT_I44416,
"067bfd75aa85ff9bae91fa3e0edd1e3e"},
{"park_joy_90p_12_420.y4m", 12, VPX_IMG_FMT_I42016,
"9e6d8f6508c6e55625f6b697bc461cef"},
{"park_joy_90p_12_422.y4m", 12, VPX_IMG_FMT_I42216,
"b239c6b301c0b835485be349ca83a7e3"},
{"park_joy_90p_12_444.y4m", 12, VPX_IMG_FMT_I44416,
"5a6481a550821dab6d0192f5c63845e9"},
};
static void write_image_file(const vpx_image_t *img, FILE *file) {
int plane, y;
for (plane = 0; plane < 3; ++plane) {
const unsigned char *buf = img->planes[plane];
const int stride = img->stride[plane];
const int bytes_per_sample = (img->fmt & VPX_IMG_FMT_HIGH) ? 2 : 1;
const int h = (plane ? (img->d_h + img->y_chroma_shift) >>
img->y_chroma_shift : img->d_h);
const int w = (plane ? (img->d_w + img->x_chroma_shift) >>
img->x_chroma_shift : img->d_w);
for (y = 0; y < h; ++y) {
fwrite(buf, bytes_per_sample, w, file);
buf += stride;
}
}
}
class Y4mVideoSourceTest
: public ::testing::TestWithParam<test_entry_type>,
public ::libvpx_test::Y4mVideoSource {
protected:
Y4mVideoSourceTest() : Y4mVideoSource("", 0, 0) {}
virtual ~Y4mVideoSourceTest() {
CloseSource();
}
virtual void Init(const std::string &file_name, int limit) {
file_name_ = file_name;
start_ = 0;
limit_ = limit;
frame_ = 0;
Begin();
}
// Checks y4m header information
void HeaderChecks(unsigned int bit_depth, vpx_img_fmt_t fmt) {
ASSERT_TRUE(input_file_ != NULL);
ASSERT_EQ(y4m_.pic_w, (int)kWidth);
ASSERT_EQ(y4m_.pic_h, (int)kHeight);
ASSERT_EQ(img()->d_w, kWidth);
ASSERT_EQ(img()->d_h, kHeight);
ASSERT_EQ(y4m_.bit_depth, bit_depth);
ASSERT_EQ(y4m_.vpx_fmt, fmt);
if (fmt == VPX_IMG_FMT_I420 || fmt == VPX_IMG_FMT_I42016) {
ASSERT_EQ(y4m_.bps, (int)y4m_.bit_depth * 3 / 2);
ASSERT_EQ(img()->x_chroma_shift, 1U);
ASSERT_EQ(img()->y_chroma_shift, 1U);
}
if (fmt == VPX_IMG_FMT_I422 || fmt == VPX_IMG_FMT_I42216) {
ASSERT_EQ(y4m_.bps, (int)y4m_.bit_depth * 2);
ASSERT_EQ(img()->x_chroma_shift, 1U);
ASSERT_EQ(img()->y_chroma_shift, 0U);
}
if (fmt == VPX_IMG_FMT_I444 || fmt == VPX_IMG_FMT_I44416) {
ASSERT_EQ(y4m_.bps, (int)y4m_.bit_depth * 3);
ASSERT_EQ(img()->x_chroma_shift, 0U);
ASSERT_EQ(img()->y_chroma_shift, 0U);
}
}
// Checks MD5 of the raw frame data
void Md5Check(const string &expected_md5) {
ASSERT_TRUE(input_file_ != NULL);
libvpx_test::MD5 md5;
for (unsigned int i = start_; i < limit_; i++) {
md5.Add(img());
Next();
}
ASSERT_EQ(string(md5.Get()), expected_md5);
}
};
TEST_P(Y4mVideoSourceTest, SourceTest) {
const test_entry_type t = GetParam();
Init(t.filename, kFrames);
HeaderChecks(t.bit_depth, t.format);
Md5Check(t.md5raw);
}
INSTANTIATE_TEST_CASE_P(C, Y4mVideoSourceTest,
::testing::ValuesIn(kY4mTestVectors));
class Y4mVideoWriteTest
: public Y4mVideoSourceTest {
protected:
Y4mVideoWriteTest() : Y4mVideoSourceTest() {}
virtual void ReplaceInputFp(FILE *input_file) {
CloseSource();
frame_ = 0;
input_file_ = input_file;
rewind(input_file_);
ReadSourceToStart();
}
// Writes out a y4m file and then reads it back
void WriteY4mAndReadBack() {
ASSERT_TRUE(input_file_ != NULL);
char buf[Y4M_BUFFER_SIZE] = {0};
const struct VpxRational framerate = {y4m_.fps_n, y4m_.fps_d};
FILE *out_file = libvpx_test::OpenTempOutFile();
ASSERT_TRUE(out_file != NULL);
y4m_write_file_header(buf, sizeof(buf),
kWidth, kHeight,
&framerate, y4m_.vpx_fmt,
y4m_.bit_depth);
fputs(buf, out_file);
for (unsigned int i = start_; i < limit_; i++) {
y4m_write_frame_header(buf, sizeof(buf));
fputs(buf, out_file);
write_image_file(img(), out_file);
Next();
}
ReplaceInputFp(out_file);
}
virtual void Init(const std::string &file_name, int limit) {
Y4mVideoSourceTest::Init(file_name, limit);
WriteY4mAndReadBack();
}
};
TEST_P(Y4mVideoWriteTest, WriteTest) {
const test_entry_type t = GetParam();
Init(t.filename, kFrames);
HeaderChecks(t.bit_depth, t.format);
Md5Check(t.md5raw);
}
INSTANTIATE_TEST_CASE_P(C, Y4mVideoWriteTest,
::testing::ValuesIn(kY4mTestVectors));
} // namespace
...@@ -38,24 +38,30 @@ class Y4mVideoSource : public VideoSource { ...@@ -38,24 +38,30 @@ class Y4mVideoSource : public VideoSource {
CloseSource(); CloseSource();
} }
virtual void Begin() { virtual void OpenSource() {
CloseSource(); CloseSource();
input_file_ = OpenTestDataFile(file_name_); input_file_ = OpenTestDataFile(file_name_);
ASSERT_TRUE(input_file_ != NULL) << "Input file open failed. Filename: " ASSERT_TRUE(input_file_ != NULL) << "Input file open failed. Filename: "
<< file_name_; << file_name_;
}
y4m_input_open(&y4m_, input_file_, NULL, 0, 0); virtual void ReadSourceToStart() {
ASSERT_TRUE(input_file_ != NULL);
ASSERT_FALSE(y4m_input_open(&y4m_, input_file_, NULL, 0, 0));
framerate_numerator_ = y4m_.fps_n; framerate_numerator_ = y4m_.fps_n;
framerate_denominator_ = y4m_.fps_d; framerate_denominator_ = y4m_.fps_d;
frame_ = 0; frame_ = 0;
for (unsigned int i = 0; i < start_; i++) { for (unsigned int i = 0; i < start_; i++) {
Next(); Next();
} }
FillFrame(); FillFrame();
} }
virtual void Begin() {
OpenSource();
ReadSourceToStart();
}
virtual void Next() { virtual void Next() {
++frame_; ++frame_;
FillFrame(); FillFrame();
......
...@@ -90,6 +90,7 @@ struct VpxInputContext { ...@@ -90,6 +90,7 @@ struct VpxInputContext {
uint32_t width; uint32_t width;
uint32_t height; uint32_t height;
vpx_img_fmt_t fmt; vpx_img_fmt_t fmt;
vpx_bit_depth_t bit_depth;
int only_i420; int only_i420;
uint32_t fourcc; uint32_t fourcc;
struct VpxRational framerate; struct VpxRational framerate;
......
...@@ -31,6 +31,7 @@ static void yuvconfig2image(vpx_image_t *img, const YV12_BUFFER_CONFIG *yv12, ...@@ -31,6 +31,7 @@ static void yuvconfig2image(vpx_image_t *img, const YV12_BUFFER_CONFIG *yv12,
img->fmt = VPX_IMG_FMT_I420; img->fmt = VPX_IMG_FMT_I420;
bps = 12; bps = 12;
} }
img->bit_depth = 8;
img->w = yv12->y_stride; img->w = yv12->y_stride;
img->h = ALIGN_POWER_OF_TWO(yv12->y_height + 2 * VP9_ENC_BORDER_IN_PIXELS, 3); img->h = ALIGN_POWER_OF_TWO(yv12->y_height + 2 * VP9_ENC_BORDER_IN_PIXELS, 3);
img->d_w = yv12->y_crop_width; img->d_w = yv12->y_crop_width;
......
...@@ -40,13 +40,13 @@ static void img_buf_free(void *memblk) { ...@@ -40,13 +40,13 @@ static void img_buf_free(void *memblk) {
} }
} }
static vpx_image_t *img_alloc_helper(vpx_image_t *img, static vpx_image_t *img_alloc_helper(vpx_image_t *img,
vpx_img_fmt_t fmt, vpx_img_fmt_t fmt,
unsigned int d_w, unsigned int d_w,
unsigned int d_h, unsigned int d_h,
unsigned int buf_align, unsigned int buf_align,
unsigned int stride_align, unsigned int stride_align,
unsigned char *img_data) { unsigned char *img_data) {
unsigned int h, w, s, xcs, ycs, bps; unsigned int h, w, s, xcs, ycs, bps;
int align; int align;
...@@ -94,6 +94,21 @@ static vpx_image_t *img_alloc_helper(vpx_image_t *img, ...@@ -94,6 +94,21 @@ static vpx_image_t *img_alloc_helper(vpx_image_t *img,
case VPX_IMG_FMT_VPXYV12: case VPX_IMG_FMT_VPXYV12:
bps = 12; bps = 12;
break; break;
case VPX_IMG_FMT_I422:
bps = 16;
break;
case VPX_IMG_FMT_I444:
bps = 24;
break;
case VPX_IMG_FMT_I42016:
bps = 24;
break;
case VPX_IMG_FMT_I42216:
bps = 32;
break;
case VPX_IMG_FMT_I44416:
bps = 48;
break;
default: default:
bps = 16; bps = 16;
break; break;
...@@ -105,6 +120,9 @@ static vpx_image_t *img_alloc_helper(vpx_image_t *img, ...@@ -105,6 +120,9 @@ static vpx_image_t *img_alloc_helper(vpx_image_t *img,
case VPX_IMG_FMT_YV12: case VPX_IMG_FMT_YV12:
case VPX_IMG_FMT_VPXI420: case VPX_IMG_FMT_VPXI420:
case VPX_IMG_FMT_VPXYV12: case VPX_IMG_FMT_VPXYV12:
case VPX_IMG_FMT_I422:
case VPX_IMG_FMT_I42016:
case VPX_IMG_FMT_I42216:
xcs = 1; xcs = 1;
break; break;
default: default:
...@@ -156,6 +174,7 @@ static vpx_image_t *img_alloc_helper(vpx_image_t *img, ...@@ -156,6 +174,7 @@ static vpx_image_t *img_alloc_helper(vpx_image_t *img,
goto fail; goto fail;
img->fmt = fmt; img->fmt = fmt;
img->bit_depth = (fmt & VPX_IMG_FMT_HIGH) ? 16 : 8;
img->w = w; img->w = w;
img->h = h; img->h = h;
img->x_chroma_shift = xcs; img->x_chroma_shift = xcs;
......
...@@ -212,6 +212,15 @@ extern "C" { ...@@ -212,6 +212,15 @@ extern "C" {
vpx_codec_priv_t *priv; /**< Algorithm private storage */ vpx_codec_priv_t *priv; /**< Algorithm private storage */
} vpx_codec_ctx_t; } vpx_codec_ctx_t;
/*!\brief Bit depth for codec
* *
* This enumeration determines the bit depth of the codec.
*/
typedef enum vpx_bit_depth {
VPX_BITS_8, /**< 8 bits */
VPX_BITS_10, /**< 10 bits */
VPX_BITS_12 /**< 12 bits */
} vpx_bit_depth_t;
/* /*
* Library Version Number Interface * Library Version Number Interface
......
...@@ -103,8 +103,9 @@ extern "C" { ...@@ -103,8 +103,9 @@ extern "C" {
vpx_img_fmt_t fmt; /**< Image Format */ vpx_img_fmt_t fmt; /**< Image Format */
/* Image storage dimensions */ /* Image storage dimensions */
unsigned int w; /**< Stored image width */ unsigned int w; /**< Stored image width */
unsigned int h; /**< Stored image height */ unsigned int h; /**< Stored image height */
unsigned int bit_depth; /**< Stored image bit-depth */
/* Image display dimensions */ /* Image display dimensions */
unsigned int d_w; /**< Displayed image width */ unsigned int d_w; /**< Displayed image width */
......
...@@ -900,7 +900,8 @@ int main_loop(int argc, const char **argv_) { ...@@ -900,7 +900,8 @@ int main_loop(int argc, const char **argv_) {
len = y4m_write_file_header(buf, sizeof(buf), len = y4m_write_file_header(buf, sizeof(buf),
vpx_input_ctx.width, vpx_input_ctx.width,
vpx_input_ctx.height, vpx_input_ctx.height,
&vpx_input_ctx.framerate, img->fmt); &vpx_input_ctx.framerate,
img->fmt, 8);
if (do_md5) { if (do_md5) {
MD5Update(&md5_ctx, (md5byte *)buf, (unsigned int)len); MD5Update(&md5_ctx, (md5byte *)buf, (unsigned int)len);
} else { } else {
......
...@@ -756,6 +756,7 @@ void open_input_file(struct VpxInputContext *input) { ...@@ -756,6 +756,7 @@ void open_input_file(struct VpxInputContext *input) {
input->framerate.numerator = input->y4m.fps_n; input->framerate.numerator = input->y4m.fps_n;
input->framerate.denominator = input->y4m.fps_d; input->framerate.denominator = input->y4m.fps_d;
input->fmt = input->y4m.vpx_fmt; input->fmt = input->y4m.vpx_fmt;
input->bit_depth = input->y4m.bit_depth;
} else } else
fatal("Unsupported Y4M stream."); fatal("Unsupported Y4M stream.");
} else if (input->detect.buf_read == 4 && fourcc_is_ivf(input->detect.buf)) { } else if (input->detect.buf_read == 4 && fourcc_is_ivf(input->detect.buf)) {
...@@ -1533,6 +1534,7 @@ int main(int argc, const char **argv_) { ...@@ -1533,6 +1534,7 @@ int main(int argc, const char **argv_) {
input.framerate.numerator = 30; input.framerate.numerator = 30;
input.framerate.denominator = 1; input.framerate.denominator = 1;
input.only_i420 = 1; input.only_i420 = 1;
input.bit_depth = 0;
/* First parse the global configuration values, because we want to apply /* First parse the global configuration values, because we want to apply
* other parameters on top of the default configuration provided by the * other parameters on top of the default configuration provided by the
......
...@@ -8,16 +8,48 @@ ...@@ -8,16 +8,48 @@
* be found in the AUTHORS file in the root of the source tree. * be found in the AUTHORS file in the root of the source tree.
*/ */
#include <assert.h>
#include "./y4menc.h" #include "./y4menc.h"
int y4m_write_file_header(char *buf, size_t len, int width, int height, int y4m_write_file_header(char *buf, size_t len, int width, int height,
const struct VpxRational *framerate, const struct VpxRational *framerate,
vpx_img_fmt_t fmt) { vpx_img_fmt_t fmt, unsigned int bit_depth) {
const char *const color = fmt == VPX_IMG_FMT_444A ? "C444alpha\n" : const char *color;
fmt == VPX_IMG_FMT_I444 ? "C444\n" : switch (bit_depth) {
fmt == VPX_IMG_FMT_I422 ? "C422\n" : case 8:
"C420jpeg\n"; color = fmt == VPX_IMG_FMT_444A ? "C444alpha\n" :
fmt == VPX_IMG_FMT_I444 ? "C444\n" :
fmt == VPX_IMG_FMT_I422 ? "C422\n" :
"C420jpeg\n";
break;
case 9:
color = fmt == VPX_IMG_FMT_I44416 ? "C444p9 XYSCSS=444P9\n" :
fmt == VPX_IMG_FMT_I42216 ? "C422p9 XYSCSS=422P9\n" :
"C420p9 XYSCSS=420P9\n";
break;
case 10:
color = fmt == VPX_IMG_FMT_I44416 ? "C444p10 XYSCSS=444P10\n" :
fmt == VPX_IMG_FMT_I42216 ? "C422p10 XYSCSS=422P10\n" :
"C420p10 XYSCSS=420P10\n";
break;
case 12:
color = fmt == VPX_IMG_FMT_I44416 ? "C444p12 XYSCSS=444P12\n" :
fmt == VPX_IMG_FMT_I42216 ? "C422p12 XYSCSS=422P12\n" :
"C420p12 XYSCSS=420P12\n";
break;
case 14:
color = fmt == VPX_IMG_FMT_I44416 ? "C444p14 XYSCSS=444P14\n" :
fmt == VPX_IMG_FMT_I42216 ? "C422p14 XYSCSS=422P14\n" :
"C420p14 XYSCSS=420P14\n";
break;
case 16:
color = fmt == VPX_IMG_FMT_I44416 ? "C444p16 XYSCSS=444P16\n" :
fmt == VPX_IMG_FMT_I42216 ? "C422p16 XYSCSS=422P16\n" :
"C420p16 XYSCSS=420P16\n";
break;
default:
assert(0);
}
return snprintf(buf, len, "YUV4MPEG2 W%u H%u F%u:%u I%c %s", width, height, return snprintf(buf, len, "YUV4MPEG2 W%u H%u F%u:%u I%c %s", width, height,
framerate->numerator, framerate->denominator, 'p', color); framerate->numerator, framerate->denominator, 'p', color);
} }
......
...@@ -23,7 +23,7 @@ extern "C" { ...@@ -23,7 +23,7 @@ extern "C" {
int y4m_write_file_header(char *buf, size_t len, int width, int height, int y4m_write_file_header(char *buf, size_t len, int width, int height,
const struct VpxRational *framerate, const struct VpxRational *framerate,
vpx_img_fmt_t fmt); vpx_img_fmt_t fmt, unsigned int bit_depth);
int y4m_write_frame_header(char *buf, size_t len); int y4m_write_frame_header(char *buf, size_t len);
#ifdef __cplusplus #ifdef __cplusplus
......
...@@ -737,15 +737,52 @@ int y4m_input_open(y4m_input *_y4m, FILE *_fin, char *_skip, int _nskip, ...@@ -737,15 +737,52 @@ int y4m_input_open(y4m_input *_y4m, FILE *_fin, char *_skip, int _nskip,
return -1; return -1;
} }
_y4m->vpx_fmt = VPX_IMG_FMT_I420; _y4m->vpx_fmt = VPX_IMG_FMT_I420;
_y4m->vpx_bps = 12; _y4m->bps = 12;
_y4m->bit_depth = 8;
if (strcmp(_y4m->chroma_type, "420") == 0 || if (strcmp(_y4m->chroma_type, "420") == 0 ||
strcmp(_y4m->chroma_type, "420jpeg") == 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->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->dst_buf_read_sz = _y4m->pic_w * _y4m->pic_h
+ 2 * ((_y4m->pic_w + 1) / 2) * ((_y4m->pic_h + 1) / 2); + 2 * ((_y4m->pic_w + 1) / 2) * ((_y4m->pic_h + 1) / 2);
/*Natively supported: no conversion required.*/ /* Natively supported: no conversion required. */
_y4m->aux_buf_sz = _y4m->aux_buf_read_sz = 0; _y4m->aux_buf_sz = _y4m->aux_buf_read_sz = 0;
_y4m->convert = y4m_convert_null; _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));
/* 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;
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));
/* 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;
if (only_420) {
fprintf(stderr, "Unsupported conversion from 420p12 to 420jpeg\n");
return -1;
}
} else if (strcmp(_y4m->chroma_type, "420mpeg2") == 0) { } 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->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->dst_buf_read_sz = _y4m->pic_w * _y4m->pic_h;
...@@ -786,7 +823,7 @@ int y4m_input_open(y4m_input *_y4m, FILE *_fin, char *_skip, int _nskip, ...@@ -786,7 +823,7 @@ int y4m_input_open(y4m_input *_y4m, FILE *_fin, char *_skip, int _nskip,
_y4m->convert = y4m_convert_422_420jpeg; _y4m->convert = y4m_convert_422_420jpeg;
} else { } else {
_y4m->vpx_fmt = VPX_IMG_FMT_I422; _y4m->vpx_fmt = VPX_IMG_FMT_I422;
_y4m->vpx_bps = 16; _y4m->bps = 16;
_y4m->dst_c_dec_h = _y4m->src_c_dec_h; _y4m->dst_c_dec_h = _y4m->src_c_dec_h;
_y4m->dst_c_dec_v = _y4m->src_c_dec_v; _y4m->dst_c_dec_v = _y4m->src_c_dec_v;
_y4m->dst_buf_read_sz = _y4m->pic_w * _y4m->pic_h _y4m->dst_buf_read_sz = _y4m->pic_w * _y4m->pic_h
...@@ -794,7 +831,39 @@ int y4m_input_open(y4m_input *_y4m, FILE *_fin, char *_skip, int _nskip, ...@@ -794,7 +831,39 @@ int y4m_input_open(y4m_input *_y4m, FILE *_fin, char *_skip, int _nskip,
/*Natively supported: no conversion required.*/ /*Natively supported: no conversion required.*/
_y4m->aux_buf_sz = _y4m->aux_buf_read_sz = 0; _y4m->aux_buf_sz = _y4m->aux_buf_read_sz = 0;
_y4m->convert = y4m_convert_null; _y4m->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;
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;
if (only_420) {
fprintf(stderr, "Unsupported conversion from 422p12 to 420jpeg\n");
return -1;
}
} else if (strcmp(_y4m->chroma_type, "411") == 0) {