Commit 44d89495 authored by Timothy B. Terriberry's avatar Timothy B. Terriberry

Add support for reading YUV4MPEG2 files to ivfenc.

A large collection of example files may be found at
 http://media.xiph.org/video/derf/
This also fixes a bug in ivfenc for uncompressed IVF input, which previously
 appeared not to skip past the file header the second time it opened the file.
I don't actually have an IVF file with which to test this fix, however.

Change-Id: Id69a1e11a3fa16c4a4fa8944e880bcea090cd52b
parent cbf12db9
...@@ -2,3 +2,6 @@ ...@@ -2,3 +2,6 @@
# Name or Organization <email address> # Name or Organization <email address>
Google Inc. Google Inc.
The Mozilla Foundation
Timothy B. Terriberry <tterriberry@mozilla.com>
The Xiph.Org Foundation
...@@ -19,8 +19,9 @@ ivfdec.SRCS += args.c args.h vpx_ports/config.h ...@@ -19,8 +19,9 @@ ivfdec.SRCS += args.c args.h vpx_ports/config.h
ivfdec.GUID = BA5FE66F-38DD-E034-F542-B1578C5FB950 ivfdec.GUID = BA5FE66F-38DD-E034-F542-B1578C5FB950
ivfdec.DESCRIPTION = Full featured decoder ivfdec.DESCRIPTION = Full featured decoder
UTILS-$(CONFIG_ENCODERS) += ivfenc.c UTILS-$(CONFIG_ENCODERS) += ivfenc.c
ivfenc.SRCS += args.c args.h vpx_ports/config.h ivfenc.SRCS += args.c args.h y4minput.c y4minput.h
ivfenc.SRCS += vpx_ports/mem_ops.h vpx_ports/mem_ops_aligned.h ivfenc.SRCS += vpx_ports/config.h vpx_ports/mem_ops.h
ivfenc.SRCS += vpx_ports/mem_ops_aligned.h
ivfenc.GUID = 548DEC74-7A15-4B2B-AFC3-AA102E7C25C1 ivfenc.GUID = 548DEC74-7A15-4B2B-AFC3-AA102E7C25C1
ivfenc.DESCRIPTION = Full featured encoder ivfenc.DESCRIPTION = Full featured encoder
......
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
#include "vpx/vp8cx.h" #include "vpx/vp8cx.h"
#include "vpx_ports/mem_ops.h" #include "vpx_ports/mem_ops.h"
#include "vpx_ports/vpx_timer.h" #include "vpx_ports/vpx_timer.h"
#include "y4minput.h"
static const char *exec_name; static const char *exec_name;
...@@ -217,49 +218,65 @@ vpx_fixed_buf_t stats_get(stats_io_t *stats) ...@@ -217,49 +218,65 @@ vpx_fixed_buf_t stats_get(stats_io_t *stats)
return stats->buf; return stats->buf;
} }
enum video_file_type
{
FILE_TYPE_RAW,
FILE_TYPE_IVF,
FILE_TYPE_Y4M
};
#define IVF_FRAME_HDR_SZ (4+8) /* 4 byte size + 8 byte timestamp */ #define IVF_FRAME_HDR_SZ (4+8) /* 4 byte size + 8 byte timestamp */
static int read_frame(FILE *f, vpx_image_t *img, unsigned int is_ivf) static int read_frame(FILE *f, vpx_image_t *img, unsigned int file_type,
y4m_input *y4m)
{ {
int plane = 0; int plane = 0;
if (is_ivf) if (file_type == FILE_TYPE_Y4M)
{ {
char junk[IVF_FRAME_HDR_SZ]; if (y4m_input_fetch_frame(y4m, f, img) < 0)
return 0;
/* Skip the frame header. We know how big the frame should be. See
* write_ivf_frame_header() for documentation on the frame header
* layout.
*/
fread(junk, 1, IVF_FRAME_HDR_SZ, f);
} }
else
for (plane = 0; plane < 3; plane++)
{ {
unsigned char *ptr; if (file_type == FILE_TYPE_IVF)
int w = (plane ? (1 + img->d_w) / 2 : img->d_w);
int h = (plane ? (1 + img->d_h) / 2 : img->d_h);
int r;
/* Determine the correct plane based on the image format. The for-loop
* always counts in Y,U,V order, but this may not match the order of
* the data on disk.
*/
switch (plane)
{ {
case 1: char junk[IVF_FRAME_HDR_SZ];
ptr = img->planes[img->fmt==VPX_IMG_FMT_YV12? VPX_PLANE_V : VPX_PLANE_U];
break; /* Skip the frame header. We know how big the frame should be. See
case 2: * write_ivf_frame_header() for documentation on the frame header
ptr = img->planes[img->fmt==VPX_IMG_FMT_YV12?VPX_PLANE_U : VPX_PLANE_V]; * layout.
break; */
default: fread(junk, 1, IVF_FRAME_HDR_SZ, f);
ptr = img->planes[plane];
} }
for (r = 0; r < h; r++) for (plane = 0; plane < 3; plane++)
{ {
fread(ptr, 1, w, f); unsigned char *ptr;
ptr += img->stride[plane]; int w = (plane ? (1 + img->d_w) / 2 : img->d_w);
int h = (plane ? (1 + img->d_h) / 2 : img->d_h);
int r;
/* Determine the correct plane based on the image format. The for-loop
* always counts in Y,U,V order, but this may not match the order of
* the data on disk.
*/
switch (plane)
{
case 1:
ptr = img->planes[img->fmt==VPX_IMG_FMT_YV12? VPX_PLANE_V : VPX_PLANE_U];
break;
case 2:
ptr = img->planes[img->fmt==VPX_IMG_FMT_YV12?VPX_PLANE_U : VPX_PLANE_V];
break;
default:
ptr = img->planes[plane];
}
for (r = 0; r < h; r++)
{
fread(ptr, 1, w, f);
ptr += img->stride[plane];
}
} }
} }
...@@ -267,6 +284,20 @@ static int read_frame(FILE *f, vpx_image_t *img, unsigned int is_ivf) ...@@ -267,6 +284,20 @@ static int read_frame(FILE *f, vpx_image_t *img, unsigned int is_ivf)
} }
unsigned int file_is_y4m(FILE *infile,
y4m_input *y4m)
{
char raw_hdr[4];
if (fread(raw_hdr, 1, 4, infile) == 4 &&
memcmp(raw_hdr, "YUV4", 4) == 0 &&
y4m_input_open(y4m, infile, raw_hdr, 4) >= 0)
{
return 1;
}
rewind(infile);
return 0;
}
#define IVF_FILE_HDR_SZ (32) #define IVF_FILE_HDR_SZ (32)
unsigned int file_is_ivf(FILE *infile, unsigned int file_is_ivf(FILE *infile,
unsigned int *fourcc, unsigned int *fourcc,
...@@ -568,8 +599,10 @@ int main(int argc, const char **argv_) ...@@ -568,8 +599,10 @@ int main(int argc, const char **argv_)
static const int *ctrl_args_map = NULL; static const int *ctrl_args_map = NULL;
int verbose = 0, show_psnr = 0; int verbose = 0, show_psnr = 0;
int arg_use_i420 = 1; int arg_use_i420 = 1;
int arg_have_timebase = 0;
unsigned long cx_time = 0; unsigned long cx_time = 0;
unsigned int is_ivf, fourcc; unsigned int file_type, fourcc;
y4m_input y4m;
exec_name = argv_[0]; exec_name = argv_[0];
...@@ -686,7 +719,10 @@ int main(int argc, const char **argv_) ...@@ -686,7 +719,10 @@ int main(int argc, const char **argv_)
else if (arg_match(&arg, &height, argi)) else if (arg_match(&arg, &height, argi))
cfg.g_h = arg_parse_uint(&arg); cfg.g_h = arg_parse_uint(&arg);
else if (arg_match(&arg, &timebase, argi)) else if (arg_match(&arg, &timebase, argi))
{
cfg.g_timebase = arg_parse_rational(&arg); cfg.g_timebase = arg_parse_rational(&arg);
arg_have_timebase = 1;
}
else if (arg_match(&arg, &error_resilient, argi)) else if (arg_match(&arg, &error_resilient, argi))
cfg.g_error_resilient = arg_parse_uint(&arg); cfg.g_error_resilient = arg_parse_uint(&arg);
else if (arg_match(&arg, &lag_in_frames, argi)) else if (arg_match(&arg, &lag_in_frames, argi))
...@@ -808,10 +844,24 @@ int main(int argc, const char **argv_) ...@@ -808,10 +844,24 @@ int main(int argc, const char **argv_)
return EXIT_FAILURE; return EXIT_FAILURE;
} }
is_ivf = file_is_ivf(infile, &fourcc, &cfg.g_w, &cfg.g_h); if (file_is_y4m(infile, &y4m))
if (is_ivf)
{ {
file_type = FILE_TYPE_Y4M;
cfg.g_w = y4m.pic_w;
cfg.g_h = y4m.pic_h;
/* Use the frame rate from the file only if none was specified on the
* command-line.
*/
if (!arg_have_timebase)
{
cfg.g_timebase.num = y4m.fps_d;
cfg.g_timebase.den = y4m.fps_n;
}
arg_use_i420 = 0;
}
else if (file_is_ivf(infile, &fourcc, &cfg.g_w, &cfg.g_h))
{
file_type = FILE_TYPE_IVF;
switch (fourcc) switch (fourcc)
{ {
case 0x32315659: case 0x32315659:
...@@ -825,6 +875,8 @@ int main(int argc, const char **argv_) ...@@ -825,6 +875,8 @@ int main(int argc, const char **argv_)
return EXIT_FAILURE; return EXIT_FAILURE;
} }
} }
else
file_type = FILE_TYPE_RAW;
fclose(infile); fclose(infile);
...@@ -869,8 +921,14 @@ int main(int argc, const char **argv_) ...@@ -869,8 +921,14 @@ int main(int argc, const char **argv_)
SHOW(kf_max_dist); SHOW(kf_max_dist);
} }
vpx_img_alloc(&raw, arg_use_i420 ? VPX_IMG_FMT_I420 : VPX_IMG_FMT_YV12, if (file_type == FILE_TYPE_Y4M)
cfg.g_w, cfg.g_h, 1); /*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
vpx_img_alloc(&raw, arg_use_i420 ? VPX_IMG_FMT_I420 : VPX_IMG_FMT_YV12,
cfg.g_w, cfg.g_h, 1);
// This was added so that ivfenc will create monotically increasing // This was added so that ivfenc will create monotically increasing
// timestamps. Since we create new timestamps for alt-reference frames // timestamps. Since we create new timestamps for alt-reference frames
...@@ -894,6 +952,18 @@ int main(int argc, const char **argv_) ...@@ -894,6 +952,18 @@ int main(int argc, const char **argv_)
return EXIT_FAILURE; return EXIT_FAILURE;
} }
/*Skip the file header.*/
if (file_type == FILE_TYPE_IVF)
{
char raw_hdr[IVF_FILE_HDR_SZ];
(void)fread(raw_hdr, 1, IVF_FILE_HDR_SZ, infile);
}
else if(file_type == FILE_TYPE_Y4M)
{
char buffer[80];
(void)fgets(buffer, sizeof(buffer)/sizeof(*buffer) - 1, infile);
}
outfile = fopen(out_fn, "wb"); outfile = fopen(out_fn, "wb");
if (!outfile) if (!outfile)
...@@ -966,7 +1036,7 @@ int main(int argc, const char **argv_) ...@@ -966,7 +1036,7 @@ int main(int argc, const char **argv_)
if (!arg_limit || frames_in < arg_limit) if (!arg_limit || frames_in < arg_limit)
{ {
frame_avail = read_frame(infile, &raw, is_ivf); frame_avail = read_frame(infile, &raw, file_type, &y4m);
if (frame_avail) if (frame_avail)
frames_in++; frames_in++;
......
This diff is collapsed.
/*
* Copyright (c) 2010 The VP8 project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license and patent
* grant that can be found in the LICENSE file in the root of the source
* tree. All contributing project authors may be found in the AUTHORS
* file in the root of the source tree.
*
* Based on code from the OggTheora software codec source code,
* Copyright (C) 2002-2010 The Xiph.Org Foundation and contributors.
*/
#if !defined(_y4minput_H)
# define _y4minput_H (1)
# include <stdio.h>
# include "vpx/vpx_image.h"
typedef struct y4m_input y4m_input;
/*The function used to perform chroma conversion.*/
typedef void (*y4m_convert_func)(y4m_input *_y4m,
unsigned char *_dst,unsigned char *_src);
struct y4m_input{
int pic_w;
int pic_h;
int fps_n;
int fps_d;
int par_n;
int par_d;
char interlace;
int src_c_dec_h;
int src_c_dec_v;
int dst_c_dec_h;
int dst_c_dec_v;
char chroma_type[16];
/*The size of each converted frame buffer.*/
size_t dst_buf_sz;
/*The amount to read directly into the converted frame buffer.*/
size_t dst_buf_read_sz;
/*The size of the auxilliary buffer.*/
size_t aux_buf_sz;
/*The amount to read into the auxilliary buffer.*/
size_t aux_buf_read_sz;
y4m_convert_func convert;
unsigned char *dst_buf;
unsigned char *aux_buf;
};
int y4m_input_open(y4m_input *_y4m,FILE *_fin,char *_skip,int _nskip);
void y4m_input_close(y4m_input *_y4m);
int y4m_input_fetch_frame(y4m_input *_y4m,FILE *_fin,vpx_image_t *img);
#endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment