From: John Koleszar Date: Thu, 10 Jun 2010 21:10:12 +0000 (-0400) Subject: ivfenc: support reading/writing from a pipe X-Git-Tag: v0.9.1~19 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=3245d463c4a3e44185722c1e108d20576cd3f9f8;p=libvpx 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 --- diff --git a/ivfenc.c b/ivfenc.c index c20df5b96..b13db6522 100644 --- a/ivfenc.c +++ b/ivfenc.c @@ -1,10 +1,10 @@ /* * Copyright (c) 2010 The VP8 project authors. All Rights Reserved. * - * Use of this source code is governed by a BSD-style license + * 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 + * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ @@ -55,8 +55,8 @@ void die(const char *fmt, ...) { va_list ap; va_start(ap, fmt); - vprintf(fmt, ap); - printf("\n"); + vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); 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); - printf("%s: %s\n", s, vpx_codec_error(ctx)); + fprintf(stderr, "%s: %s\n", s, vpx_codec_error(ctx)); if (detail) - printf(" %s\n", detail); + fprintf(stderr, " %s\n", detail); exit(EXIT_FAILURE); } @@ -226,9 +226,15 @@ enum video_file_type FILE_TYPE_Y4M }; +struct detect_buffer { + char buf[4]; + int valid; +}; + + #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, - y4m_input *y4m) + y4m_input *y4m, struct detect_buffer *detect) { 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++) { - fread(ptr, 1, w, f); + if (detect->valid) + { + memcpy(ptr, detect->buf, 4); + fread(ptr+4, 1, w-4, f); + detect->valid = 0; + } + else + fread(ptr, 1, w, f); + 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, - y4m_input *y4m) + y4m_input *y4m, + char detect[4]) { - 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) + if(memcmp(detect, "YUV4", 4) == 0 && + y4m_input_open(y4m, infile, detect, 4) >= 0) { return 1; } - rewind(infile); return 0; } @@ -303,18 +315,21 @@ unsigned int file_is_y4m(FILE *infile, unsigned int file_is_ivf(FILE *infile, unsigned int *fourcc, unsigned int *width, - unsigned int *height) + unsigned int *height, + char detect[4]) { char raw_hdr[IVF_FILE_HDR_SZ]; int is_ivf = 0; + if(memcmp(detect, "DKIF", 4) != 0) + return 0; + /* See write_ivf_file_header() for more documentation on the file header * 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; @@ -331,8 +346,6 @@ unsigned int file_is_ivf(FILE *infile, *width = mem_get_le16(raw_hdr + 12); *height = mem_get_le16(raw_hdr + 14); } - else - rewind(infile); return is_ivf; } @@ -546,28 +559,28 @@ static void usage_exit() { int i; - printf("Usage: %s src_filename dst_filename\n", exec_name); + fprintf(stderr, "Usage: %s src_filename dst_filename\n", exec_name); - printf("\n_options:\n"); + fprintf(stderr, "\n_options:\n"); 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); - printf("\n_rate Control Options:\n"); + fprintf(stderr, "\n_rate Control Options:\n"); 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); - printf("\n_keyframe Placement Options:\n"); + fprintf(stderr, "\n_keyframe Placement Options:\n"); arg_show_usage(stdout, kf_args); #if CONFIG_VP8_ENCODER - printf("\n_vp8 Specific Options:\n"); + fprintf(stderr, "\n_vp8 Specific Options:\n"); arg_show_usage(stdout, vp8_args); #endif - printf("\n" + fprintf(stderr, "\n" "Included encoders:\n" "\n"); for (i = 0; i < sizeof(codecs) / sizeof(codecs[0]); i++) - printf(" %-6s - %s\n", + fprintf(stderr, " %-6s - %s\n", codecs[i].name, 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 */ 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); arg_passes = one_pass_only; } @@ -701,7 +714,8 @@ int main(int argc, const char **argv_) 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; } @@ -761,24 +775,27 @@ int main(int argc, const char **argv_) cfg.rc_2pass_vbr_bias_pct = arg_parse_uint(&arg); if (arg_passes < 2) - printf("Warning: option %s ignored in one-pass mode.\n", - arg.name); + fprintf(stderr, + "Warning: option %s ignored in one-pass mode.\n", + arg.name); } else if (arg_match(&arg, &minsection_pct, argi)) { cfg.rc_2pass_vbr_minsection_pct = arg_parse_uint(&arg); if (arg_passes < 2) - printf("Warning: option %s ignored in one-pass mode.\n", - arg.name); + fprintf(stderr, + "Warning: option %s ignored in one-pass mode.\n", + arg.name); } else if (arg_match(&arg, &maxsection_pct, argi)) { cfg.rc_2pass_vbr_maxsection_pct = arg_parse_uint(&arg); if (arg_passes < 2) - printf("Warning: option %s ignored in one-pass mode.\n", - arg.name); + fprintf(stderr, + "Warning: option %s ignored in one-pass mode.\n", + arg.name); } else if (arg_match(&arg, &kf_min_dist, argi)) cfg.kf_min_dist = arg_parse_uint(&arg); @@ -826,7 +843,7 @@ int main(int argc, const char **argv_) /* Check for unrecognized options */ for (argi = argv; *argi; argi++) - if (argi[0][0] == '-') + if (argi[0][0] == '-' && argi[0][1]) die("Error: Unrecognized option %s\n", *argi); /* Handle non-option arguments */ @@ -836,140 +853,126 @@ int main(int argc, const char **argv_) if (!in_fn || !out_fn) usage_exit(); - /* Parse certain options from the input file, if possible */ - infile = fopen(in_fn, "rb"); - - if (!infile) - { - printf("Failed to open input file"); - return EXIT_FAILURE; - } - - if (file_is_y4m(infile, &y4m)) - { - 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) - { - case 0x32315659: - arg_use_i420 = 0; - break; - case 0x30323449: - arg_use_i420 = 1; - break; - default: - printf("Unsupported fourcc (%08x) in IVF\n", fourcc); - return EXIT_FAILURE; - } - } - 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)); - printf("Source file: %s Format: %s\n", in_fn, arg_use_i420 ? "I420" : "YV12"); - printf("Destination file: %s\n", out_fn); - printf("Encoder parameters:\n"); - - SHOW(g_usage); - SHOW(g_threads); - SHOW(g_profile); - SHOW(g_w); - SHOW(g_h); - SHOW(g_timebase.num); - SHOW(g_timebase.den); - SHOW(g_error_resilient); - SHOW(g_pass); - SHOW(g_lag_in_frames); - SHOW(rc_dropframe_thresh); - SHOW(rc_resize_allowed); - SHOW(rc_resize_up_thresh); - SHOW(rc_resize_down_thresh); - SHOW(rc_end_usage); - SHOW(rc_target_bitrate); - SHOW(rc_min_quantizer); - SHOW(rc_max_quantizer); - SHOW(rc_undershoot_pct); - SHOW(rc_overshoot_pct); - SHOW(rc_buf_sz); - SHOW(rc_buf_initial_sz); - SHOW(rc_buf_optimal_sz); - SHOW(rc_2pass_vbr_bias_pct); - SHOW(rc_2pass_vbr_minsection_pct); - SHOW(rc_2pass_vbr_maxsection_pct); - SHOW(kf_mode); - SHOW(kf_min_dist); - SHOW(kf_max_dist); - } - - if (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 - 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 - // timestamps. Since we create new timestamps for alt-reference frames - // we need to make room in the series of timestamps. Since there can - // only be 1 alt-ref frame ( current bitstream) multiplying by 2 - // gives us enough room. - 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; + struct detect_buffer detect; - infile = fopen(in_fn, "rb"); + /* Parse certain options from the input file, if possible */ + infile = strcmp(in_fn, "-") ? fopen(in_fn, "rb") : stdin; if (!infile) { - printf("Failed to open input file"); + fprintf(stderr, "Failed to open input file\n"); return EXIT_FAILURE; } - /*Skip the file header.*/ - if (file_type == FILE_TYPE_IVF) + fread(detect.buf, 1, 4, infile); + detect.valid = 0; + + if (file_is_y4m(infile, &y4m, detect.buf)) + { + 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, detect.buf)) { - char raw_hdr[IVF_FILE_HDR_SZ]; - (void)fread(raw_hdr, 1, IVF_FILE_HDR_SZ, infile); + file_type = FILE_TYPE_IVF; + switch (fourcc) + { + case 0x32315659: + arg_use_i420 = 0; + break; + case 0x30323449: + arg_use_i420 = 1; + break; + default: + fprintf(stderr, "Unsupported fourcc (%08x) in IVF\n", fourcc); + return EXIT_FAILURE; + } } - else if(file_type == FILE_TYPE_Y4M) + else + { + file_type = FILE_TYPE_RAW; + detect.valid = 1; + } +#define SHOW(field) fprintf(stderr, " %-28s = %d\n", #field, cfg.field) + + if (verbose && pass == 0) { - char buffer[80]; - (void)fgets(buffer, sizeof(buffer)/sizeof(*buffer) - 1, infile); + 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_threads); + SHOW(g_profile); + SHOW(g_w); + SHOW(g_h); + SHOW(g_timebase.num); + SHOW(g_timebase.den); + SHOW(g_error_resilient); + SHOW(g_pass); + SHOW(g_lag_in_frames); + SHOW(rc_dropframe_thresh); + SHOW(rc_resize_allowed); + SHOW(rc_resize_up_thresh); + SHOW(rc_resize_down_thresh); + SHOW(rc_end_usage); + SHOW(rc_target_bitrate); + SHOW(rc_min_quantizer); + SHOW(rc_max_quantizer); + SHOW(rc_undershoot_pct); + SHOW(rc_overshoot_pct); + SHOW(rc_buf_sz); + SHOW(rc_buf_initial_sz); + SHOW(rc_buf_optimal_sz); + SHOW(rc_2pass_vbr_bias_pct); + SHOW(rc_2pass_vbr_minsection_pct); + SHOW(rc_2pass_vbr_maxsection_pct); + SHOW(kf_mode); + SHOW(kf_min_dist); + SHOW(kf_max_dist); + } + + if(pass == 0) { + if (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 + 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 + // timestamps. Since we create new timestamps for alt-reference frames + // we need to make room in the series of timestamps. Since there can + // only be 1 alt-ref frame ( current bitstream) multiplying by 2 + // gives us enough room. + cfg.g_timebase.den *= 2; } - outfile = fopen(out_fn, "wb"); + outfile = strcmp(out_fn, "-") ? fopen(out_fn, "wb") : stdout; if (!outfile) { - printf("Failed to open output file"); + fprintf(stderr, "Failed to open output file\n"); return EXIT_FAILURE; } @@ -977,7 +980,7 @@ int main(int argc, const char **argv_) { 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; } } @@ -985,7 +988,7 @@ int main(int argc, const char **argv_) { if (!stats_open_mem(&stats, pass)) { - printf("Failed to open statistics store\n"); + fprintf(stderr, "Failed to open statistics store\n"); return EXIT_FAILURE; } } @@ -1020,8 +1023,8 @@ int main(int argc, const char **argv_) for (i = 0; i < arg_ctrl_cnt; i++) { if (vpx_codec_control_(&encoder, arg_ctrls[i][0], arg_ctrls[i][1])) - printf("Error: Tried to set control %d = %d\n", - arg_ctrls[i][0], arg_ctrls[i][1]); + fprintf(stderr, "Error: Tried to set control %d = %d\n", + arg_ctrls[i][0], arg_ctrls[i][1]); ctx_exit_on_error(&encoder, "Failed to control codec"); } @@ -1037,13 +1040,15 @@ int main(int argc, const char **argv_) 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) frames_in++; - printf("\rPass %d/%d frame %4d/%-4d %7ldB \033[K", pass + 1, - arg_passes, frames_in, frames_out, nbytes); + fprintf(stderr, + "\rPass %d/%d frame %4d/%-4d %7ldB \033[K", pass + 1, + arg_passes, frames_in, frames_out, nbytes); } else frame_avail = 0; @@ -1067,15 +1072,15 @@ int main(int argc, const char **argv_) { case VPX_CODEC_CX_FRAME_PKT: frames_out++; - printf(" %6luF", - (unsigned long)pkt->data.frame.sz); + fprintf(stderr, " %6luF", + (unsigned long)pkt->data.frame.sz); write_ivf_frame_header(outfile, pkt); fwrite(pkt->data.frame.buf, 1, pkt->data.frame.sz, outfile); nbytes += pkt->data.raw.sz; break; case VPX_CODEC_STATS_PKT: frames_out++; - printf(" %6luS", + fprintf(stderr, " %6luS", (unsigned long)pkt->data.twopass_stats.sz); stats_write(&stats, pkt->data.twopass_stats.buf, @@ -1089,7 +1094,7 @@ int main(int argc, const char **argv_) int i; for (i = 0; i < 4; i++) - printf("%.3lf ", pkt->data.psnr.psnr[i]); + fprintf(stderr, "%.3lf ", pkt->data.psnr.psnr[i]); } break; @@ -1104,7 +1109,8 @@ int main(int argc, const char **argv_) /* this bitrate calc is simplified and relies on the fact that this * 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, 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, @@ -1121,7 +1127,7 @@ int main(int argc, const char **argv_) fclose(outfile); stats_close(&stats); - printf("\n"); + fprintf(stderr, "\n"); if (one_pass_only) break;