ivfenc: support reading/writing from a pipe

Use - for the filename to use stdin/stdout. Update to avoid opening
the file multiple times.

Change-Id: I356356fa16bb334d4b22abc531dc03c0d95917a3
This commit is contained in:
John Koleszar
2010-06-10 17:10:12 -04:00
parent db0f26c0e2
commit 3245d463c4

180
ivfenc.c
View File

@@ -55,8 +55,8 @@ void die(const char *fmt, ...)
{ {
va_list ap; va_list ap;
va_start(ap, fmt); va_start(ap, fmt);
vprintf(fmt, ap); vfprintf(stderr, fmt, ap);
printf("\n"); fprintf(stderr, "\n");
usage_exit(); usage_exit();
} }
@@ -66,10 +66,10 @@ static void ctx_exit_on_error(vpx_codec_ctx_t *ctx, const char *s)
{ {
const char *detail = vpx_codec_error_detail(ctx); const char *detail = vpx_codec_error_detail(ctx);
printf("%s: %s\n", s, vpx_codec_error(ctx)); fprintf(stderr, "%s: %s\n", s, vpx_codec_error(ctx));
if (detail) if (detail)
printf(" %s\n", detail); fprintf(stderr, " %s\n", detail);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
@@ -226,9 +226,15 @@ enum video_file_type
FILE_TYPE_Y4M FILE_TYPE_Y4M
}; };
struct detect_buffer {
char buf[4];
int valid;
};
#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 file_type, static int read_frame(FILE *f, vpx_image_t *img, unsigned int file_type,
y4m_input *y4m) y4m_input *y4m, struct detect_buffer *detect)
{ {
int plane = 0; int plane = 0;
@@ -275,7 +281,15 @@ static int read_frame(FILE *f, vpx_image_t *img, unsigned int file_type,
for (r = 0; r < h; r++) for (r = 0; r < h; r++)
{ {
if (detect->valid)
{
memcpy(ptr, detect->buf, 4);
fread(ptr+4, 1, w-4, f);
detect->valid = 0;
}
else
fread(ptr, 1, w, f); fread(ptr, 1, w, f);
ptr += img->stride[plane]; ptr += img->stride[plane];
} }
} }
@@ -286,16 +300,14 @@ static int read_frame(FILE *f, vpx_image_t *img, unsigned int file_type,
unsigned int file_is_y4m(FILE *infile, unsigned int file_is_y4m(FILE *infile,
y4m_input *y4m) y4m_input *y4m,
char detect[4])
{ {
char raw_hdr[4]; if(memcmp(detect, "YUV4", 4) == 0 &&
if (fread(raw_hdr, 1, 4, infile) == 4 && y4m_input_open(y4m, infile, detect, 4) >= 0)
memcmp(raw_hdr, "YUV4", 4) == 0 &&
y4m_input_open(y4m, infile, raw_hdr, 4) >= 0)
{ {
return 1; return 1;
} }
rewind(infile);
return 0; return 0;
} }
@@ -303,18 +315,21 @@ unsigned int file_is_y4m(FILE *infile,
unsigned int file_is_ivf(FILE *infile, unsigned int file_is_ivf(FILE *infile,
unsigned int *fourcc, unsigned int *fourcc,
unsigned int *width, unsigned int *width,
unsigned int *height) unsigned int *height,
char detect[4])
{ {
char raw_hdr[IVF_FILE_HDR_SZ]; char raw_hdr[IVF_FILE_HDR_SZ];
int is_ivf = 0; int is_ivf = 0;
if(memcmp(detect, "DKIF", 4) != 0)
return 0;
/* See write_ivf_file_header() for more documentation on the file header /* See write_ivf_file_header() for more documentation on the file header
* layout. * layout.
*/ */
if (fread(raw_hdr, 1, IVF_FILE_HDR_SZ, infile) == IVF_FILE_HDR_SZ) if (fread(raw_hdr + 4, 1, IVF_FILE_HDR_SZ - 4, infile)
== IVF_FILE_HDR_SZ - 4)
{ {
if (raw_hdr[0] == 'D' && raw_hdr[1] == 'K'
&& raw_hdr[2] == 'I' && raw_hdr[3] == 'F')
{ {
is_ivf = 1; is_ivf = 1;
@@ -331,8 +346,6 @@ unsigned int file_is_ivf(FILE *infile,
*width = mem_get_le16(raw_hdr + 12); *width = mem_get_le16(raw_hdr + 12);
*height = mem_get_le16(raw_hdr + 14); *height = mem_get_le16(raw_hdr + 14);
} }
else
rewind(infile);
return is_ivf; return is_ivf;
} }
@@ -546,28 +559,28 @@ static void usage_exit()
{ {
int i; int i;
printf("Usage: %s <options> src_filename dst_filename\n", exec_name); fprintf(stderr, "Usage: %s <options> src_filename dst_filename\n", exec_name);
printf("\n_options:\n"); fprintf(stderr, "\n_options:\n");
arg_show_usage(stdout, main_args); arg_show_usage(stdout, main_args);
printf("\n_encoder Global Options:\n"); fprintf(stderr, "\n_encoder Global Options:\n");
arg_show_usage(stdout, global_args); arg_show_usage(stdout, global_args);
printf("\n_rate Control Options:\n"); fprintf(stderr, "\n_rate Control Options:\n");
arg_show_usage(stdout, rc_args); arg_show_usage(stdout, rc_args);
printf("\n_twopass Rate Control Options:\n"); fprintf(stderr, "\n_twopass Rate Control Options:\n");
arg_show_usage(stdout, rc_twopass_args); arg_show_usage(stdout, rc_twopass_args);
printf("\n_keyframe Placement Options:\n"); fprintf(stderr, "\n_keyframe Placement Options:\n");
arg_show_usage(stdout, kf_args); arg_show_usage(stdout, kf_args);
#if CONFIG_VP8_ENCODER #if CONFIG_VP8_ENCODER
printf("\n_vp8 Specific Options:\n"); fprintf(stderr, "\n_vp8 Specific Options:\n");
arg_show_usage(stdout, vp8_args); arg_show_usage(stdout, vp8_args);
#endif #endif
printf("\n" fprintf(stderr, "\n"
"Included encoders:\n" "Included encoders:\n"
"\n"); "\n");
for (i = 0; i < sizeof(codecs) / sizeof(codecs[0]); i++) for (i = 0; i < sizeof(codecs) / sizeof(codecs[0]); i++)
printf(" %-6s - %s\n", fprintf(stderr, " %-6s - %s\n",
codecs[i].name, codecs[i].name,
vpx_codec_iface_name(codecs[i].iface)); vpx_codec_iface_name(codecs[i].iface));
@@ -687,7 +700,7 @@ int main(int argc, const char **argv_)
/* DWIM: Assume the user meant passes=2 if pass=2 is specified */ /* DWIM: Assume the user meant passes=2 if pass=2 is specified */
if (one_pass_only > arg_passes) if (one_pass_only > arg_passes)
{ {
printf("Warning: Assuming --pass=%d implies --passes=%d\n", fprintf(stderr, "Warning: Assuming --pass=%d implies --passes=%d\n",
one_pass_only, one_pass_only); one_pass_only, one_pass_only);
arg_passes = one_pass_only; arg_passes = one_pass_only;
} }
@@ -701,7 +714,8 @@ int main(int argc, const char **argv_)
if (res) if (res)
{ {
printf("Failed to get config: %s\n", vpx_codec_err_to_string(res)); fprintf(stderr, "Failed to get config: %s\n",
vpx_codec_err_to_string(res));
return EXIT_FAILURE; return EXIT_FAILURE;
} }
@@ -761,7 +775,8 @@ int main(int argc, const char **argv_)
cfg.rc_2pass_vbr_bias_pct = arg_parse_uint(&arg); cfg.rc_2pass_vbr_bias_pct = arg_parse_uint(&arg);
if (arg_passes < 2) if (arg_passes < 2)
printf("Warning: option %s ignored in one-pass mode.\n", fprintf(stderr,
"Warning: option %s ignored in one-pass mode.\n",
arg.name); arg.name);
} }
else if (arg_match(&arg, &minsection_pct, argi)) else if (arg_match(&arg, &minsection_pct, argi))
@@ -769,7 +784,8 @@ int main(int argc, const char **argv_)
cfg.rc_2pass_vbr_minsection_pct = arg_parse_uint(&arg); cfg.rc_2pass_vbr_minsection_pct = arg_parse_uint(&arg);
if (arg_passes < 2) if (arg_passes < 2)
printf("Warning: option %s ignored in one-pass mode.\n", fprintf(stderr,
"Warning: option %s ignored in one-pass mode.\n",
arg.name); arg.name);
} }
else if (arg_match(&arg, &maxsection_pct, argi)) else if (arg_match(&arg, &maxsection_pct, argi))
@@ -777,7 +793,8 @@ int main(int argc, const char **argv_)
cfg.rc_2pass_vbr_maxsection_pct = arg_parse_uint(&arg); cfg.rc_2pass_vbr_maxsection_pct = arg_parse_uint(&arg);
if (arg_passes < 2) if (arg_passes < 2)
printf("Warning: option %s ignored in one-pass mode.\n", fprintf(stderr,
"Warning: option %s ignored in one-pass mode.\n",
arg.name); arg.name);
} }
else if (arg_match(&arg, &kf_min_dist, argi)) else if (arg_match(&arg, &kf_min_dist, argi))
@@ -826,7 +843,7 @@ int main(int argc, const char **argv_)
/* Check for unrecognized options */ /* Check for unrecognized options */
for (argi = argv; *argi; argi++) for (argi = argv; *argi; argi++)
if (argi[0][0] == '-') if (argi[0][0] == '-' && argi[0][1])
die("Error: Unrecognized option %s\n", *argi); die("Error: Unrecognized option %s\n", *argi);
/* Handle non-option arguments */ /* Handle non-option arguments */
@@ -836,16 +853,27 @@ int main(int argc, const char **argv_)
if (!in_fn || !out_fn) if (!in_fn || !out_fn)
usage_exit(); usage_exit();
memset(&stats, 0, sizeof(stats));
for (pass = one_pass_only ? one_pass_only - 1 : 0; pass < arg_passes; pass++)
{
int frames_in = 0, frames_out = 0;
unsigned long nbytes = 0;
struct detect_buffer detect;
/* Parse certain options from the input file, if possible */ /* Parse certain options from the input file, if possible */
infile = fopen(in_fn, "rb"); infile = strcmp(in_fn, "-") ? fopen(in_fn, "rb") : stdin;
if (!infile) if (!infile)
{ {
printf("Failed to open input file"); fprintf(stderr, "Failed to open input file\n");
return EXIT_FAILURE; return EXIT_FAILURE;
} }
if (file_is_y4m(infile, &y4m)) fread(detect.buf, 1, 4, infile);
detect.valid = 0;
if (file_is_y4m(infile, &y4m, detect.buf))
{ {
file_type = FILE_TYPE_Y4M; file_type = FILE_TYPE_Y4M;
cfg.g_w = y4m.pic_w; cfg.g_w = y4m.pic_w;
@@ -860,7 +888,7 @@ int main(int argc, const char **argv_)
} }
arg_use_i420 = 0; arg_use_i420 = 0;
} }
else if (file_is_ivf(infile, &fourcc, &cfg.g_w, &cfg.g_h)) else if (file_is_ivf(infile, &fourcc, &cfg.g_w, &cfg.g_h, detect.buf))
{ {
file_type = FILE_TYPE_IVF; file_type = FILE_TYPE_IVF;
switch (fourcc) switch (fourcc)
@@ -872,24 +900,24 @@ int main(int argc, const char **argv_)
arg_use_i420 = 1; arg_use_i420 = 1;
break; break;
default: default:
printf("Unsupported fourcc (%08x) in IVF\n", fourcc); fprintf(stderr, "Unsupported fourcc (%08x) in IVF\n", fourcc);
return EXIT_FAILURE; return EXIT_FAILURE;
} }
} }
else else
file_type = FILE_TYPE_RAW;
fclose(infile);
#define SHOW(field) printf(" %-28s = %d\n", #field, cfg.field)
if (verbose)
{ {
printf("Codec: %s\n", vpx_codec_iface_name(codec->iface)); file_type = FILE_TYPE_RAW;
printf("Source file: %s Format: %s\n", in_fn, arg_use_i420 ? "I420" : "YV12"); detect.valid = 1;
printf("Destination file: %s\n", out_fn); }
printf("Encoder parameters:\n"); #define SHOW(field) fprintf(stderr, " %-28s = %d\n", #field, cfg.field)
if (verbose && pass == 0)
{
fprintf(stderr, "Codec: %s\n", vpx_codec_iface_name(codec->iface));
fprintf(stderr, "Source file: %s Format: %s\n", in_fn,
arg_use_i420 ? "I420" : "YV12");
fprintf(stderr, "Destination file: %s\n", out_fn);
fprintf(stderr, "Encoder parameters:\n");
SHOW(g_usage); SHOW(g_usage);
SHOW(g_threads); SHOW(g_threads);
@@ -922,6 +950,7 @@ int main(int argc, const char **argv_)
SHOW(kf_max_dist); SHOW(kf_max_dist);
} }
if(pass == 0) {
if (file_type == FILE_TYPE_Y4M) if (file_type == FILE_TYPE_Y4M)
/*The Y4M reader does its own allocation. /*The Y4M reader does its own allocation.
Just initialize this here to avoid problems if we never read any Just initialize this here to avoid problems if we never read any
@@ -937,39 +966,13 @@ int main(int argc, const char **argv_)
// only be 1 alt-ref frame ( current bitstream) multiplying by 2 // only be 1 alt-ref frame ( current bitstream) multiplying by 2
// gives us enough room. // gives us enough room.
cfg.g_timebase.den *= 2; cfg.g_timebase.den *= 2;
memset(&stats, 0, sizeof(stats));
for (pass = one_pass_only ? one_pass_only - 1 : 0; pass < arg_passes; pass++)
{
int frames_in = 0, frames_out = 0;
unsigned long nbytes = 0;
infile = fopen(in_fn, "rb");
if (!infile)
{
printf("Failed to open input file");
return EXIT_FAILURE;
} }
/*Skip the file header.*/ outfile = strcmp(out_fn, "-") ? fopen(out_fn, "wb") : stdout;
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");
if (!outfile) if (!outfile)
{ {
printf("Failed to open output file"); fprintf(stderr, "Failed to open output file\n");
return EXIT_FAILURE; return EXIT_FAILURE;
} }
@@ -977,7 +980,7 @@ int main(int argc, const char **argv_)
{ {
if (!stats_open_file(&stats, stats_fn, pass)) if (!stats_open_file(&stats, stats_fn, pass))
{ {
printf("Failed to open statistics store\n"); fprintf(stderr, "Failed to open statistics store\n");
return EXIT_FAILURE; return EXIT_FAILURE;
} }
} }
@@ -985,7 +988,7 @@ int main(int argc, const char **argv_)
{ {
if (!stats_open_mem(&stats, pass)) if (!stats_open_mem(&stats, pass))
{ {
printf("Failed to open statistics store\n"); fprintf(stderr, "Failed to open statistics store\n");
return EXIT_FAILURE; return EXIT_FAILURE;
} }
} }
@@ -1020,7 +1023,7 @@ int main(int argc, const char **argv_)
for (i = 0; i < arg_ctrl_cnt; i++) for (i = 0; i < arg_ctrl_cnt; i++)
{ {
if (vpx_codec_control_(&encoder, arg_ctrls[i][0], arg_ctrls[i][1])) if (vpx_codec_control_(&encoder, arg_ctrls[i][0], arg_ctrls[i][1]))
printf("Error: Tried to set control %d = %d\n", fprintf(stderr, "Error: Tried to set control %d = %d\n",
arg_ctrls[i][0], arg_ctrls[i][1]); arg_ctrls[i][0], arg_ctrls[i][1]);
ctx_exit_on_error(&encoder, "Failed to control codec"); ctx_exit_on_error(&encoder, "Failed to control codec");
@@ -1037,12 +1040,14 @@ 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, file_type, &y4m); frame_avail = read_frame(infile, &raw, file_type, &y4m,
&detect);
if (frame_avail) if (frame_avail)
frames_in++; frames_in++;
printf("\rPass %d/%d frame %4d/%-4d %7ldB \033[K", pass + 1, fprintf(stderr,
"\rPass %d/%d frame %4d/%-4d %7ldB \033[K", pass + 1,
arg_passes, frames_in, frames_out, nbytes); arg_passes, frames_in, frames_out, nbytes);
} }
else else
@@ -1067,7 +1072,7 @@ int main(int argc, const char **argv_)
{ {
case VPX_CODEC_CX_FRAME_PKT: case VPX_CODEC_CX_FRAME_PKT:
frames_out++; frames_out++;
printf(" %6luF", fprintf(stderr, " %6luF",
(unsigned long)pkt->data.frame.sz); (unsigned long)pkt->data.frame.sz);
write_ivf_frame_header(outfile, pkt); write_ivf_frame_header(outfile, pkt);
fwrite(pkt->data.frame.buf, 1, pkt->data.frame.sz, outfile); fwrite(pkt->data.frame.buf, 1, pkt->data.frame.sz, outfile);
@@ -1075,7 +1080,7 @@ int main(int argc, const char **argv_)
break; break;
case VPX_CODEC_STATS_PKT: case VPX_CODEC_STATS_PKT:
frames_out++; frames_out++;
printf(" %6luS", fprintf(stderr, " %6luS",
(unsigned long)pkt->data.twopass_stats.sz); (unsigned long)pkt->data.twopass_stats.sz);
stats_write(&stats, stats_write(&stats,
pkt->data.twopass_stats.buf, pkt->data.twopass_stats.buf,
@@ -1089,7 +1094,7 @@ int main(int argc, const char **argv_)
int i; int i;
for (i = 0; i < 4; i++) for (i = 0; i < 4; i++)
printf("%.3lf ", pkt->data.psnr.psnr[i]); fprintf(stderr, "%.3lf ", pkt->data.psnr.psnr[i]);
} }
break; break;
@@ -1104,7 +1109,8 @@ int main(int argc, const char **argv_)
/* this bitrate calc is simplified and relies on the fact that this /* this bitrate calc is simplified and relies on the fact that this
* application uses 1/timebase for framerate. * application uses 1/timebase for framerate.
*/ */
printf("\rPass %d/%d frame %4d/%-4d %7ldB %7ldb/f %7"PRId64"b/s" fprintf(stderr,
"\rPass %d/%d frame %4d/%-4d %7ldB %7ldb/f %7"PRId64"b/s"
" %7lu %s (%.2f fps)\033[K", pass + 1, " %7lu %s (%.2f fps)\033[K", pass + 1,
arg_passes, frames_in, frames_out, nbytes, nbytes * 8 / frames_in, arg_passes, frames_in, frames_out, nbytes, nbytes * 8 / frames_in,
nbytes * 8 *(int64_t)cfg.g_timebase.den/2/ cfg.g_timebase.num / frames_in, nbytes * 8 *(int64_t)cfg.g_timebase.den/2/ cfg.g_timebase.num / frames_in,
@@ -1121,7 +1127,7 @@ int main(int argc, const char **argv_)
fclose(outfile); fclose(outfile);
stats_close(&stats); stats_close(&stats);
printf("\n"); fprintf(stderr, "\n");
if (one_pass_only) if (one_pass_only)
break; break;