| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (c) 2010 The WebM project authors. All Rights Reserved. | 2 * Copyright (c) 2010 The WebM project authors. All Rights Reserved. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license | 4 * Use of this source code is governed by a BSD-style license |
| 5 * that can be found in the LICENSE file in the root of the source | 5 * that can be found in the LICENSE file in the root of the source |
| 6 * tree. An additional intellectual property rights grant can be found | 6 * tree. An additional intellectual property rights grant can be found |
| 7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
| 8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
| 9 */ | 9 */ |
| 10 | 10 |
| 11 | 11 |
| 12 /* This is a simple program that reads ivf files and decodes them | 12 /* This is a simple program that reads ivf files and decodes them |
| 13 * using the new interface. Decoded frames are output as YV12 raw. | 13 * using the new interface. Decoded frames are output as YV12 raw. |
| 14 */ | 14 */ |
| 15 #include <stdio.h> | 15 #include <stdio.h> |
| 16 #include <stdlib.h> | 16 #include <stdlib.h> |
| 17 #include <stdarg.h> | 17 #include <stdarg.h> |
| 18 #include <string.h> | 18 #include <string.h> |
| 19 #include <limits.h> | 19 #include <limits.h> |
| 20 | 20 |
| 21 #define VPX_CODEC_DISABLE_COMPAT 1 | 21 #define VPX_CODEC_DISABLE_COMPAT 1 |
| 22 #include "vpx_config.h" | 22 #include "vpx_config.h" |
| 23 #include "vpx/vpx_decoder.h" | 23 #include "vpx/vpx_decoder.h" |
| 24 #include "vpx_ports/vpx_timer.h" | 24 #include "vpx_ports/vpx_timer.h" |
| 25 #if CONFIG_VP8_DECODER | 25 #if CONFIG_VP8_DECODER || CONFIG_VP9_DECODER |
| 26 #include "vpx/vp8dx.h" | 26 #include "vpx/vp8dx.h" |
| 27 #endif | 27 #endif |
| 28 #if CONFIG_MD5 | 28 #if CONFIG_MD5 |
| 29 #include "md5_utils.h" | 29 #include "md5_utils.h" |
| 30 #endif | 30 #endif |
| 31 #include "tools_common.h" | 31 #include "tools_common.h" |
| 32 #include "nestegg/include/nestegg/nestegg.h" | 32 #include "nestegg/include/nestegg/nestegg.h" |
| 33 | 33 |
| 34 #if CONFIG_OS_SUPPORT | 34 #if CONFIG_OS_SUPPORT |
| 35 #if defined(_MSC_VER) | 35 #if defined(_MSC_VER) |
| 36 #include <io.h> | 36 #include <io.h> |
| 37 #define snprintf _snprintf | 37 #define snprintf _snprintf |
| 38 #define isatty _isatty | 38 #define isatty _isatty |
| 39 #define fileno _fileno | 39 #define fileno _fileno |
| 40 #else | 40 #else |
| 41 #include <unistd.h> | 41 #include <unistd.h> |
| 42 #endif | 42 #endif |
| 43 #endif | 43 #endif |
| 44 | 44 |
| 45 #ifndef PATH_MAX | 45 #ifndef PATH_MAX |
| 46 #define PATH_MAX 256 | 46 #define PATH_MAX 256 |
| 47 #endif | 47 #endif |
| 48 | 48 |
| 49 static const char *exec_name; | 49 static const char *exec_name; |
| 50 | 50 |
| 51 #define VP8_FOURCC (0x00385056) | 51 #define VP8_FOURCC (0x00385056) |
| 52 static const struct | 52 #define VP9_FOURCC (0x00395056) |
| 53 { | 53 static const struct { |
| 54 char const *name; | 54 char const *name; |
| 55 vpx_codec_iface_t *iface; | 55 const vpx_codec_iface_t *(*iface)(void); |
| 56 unsigned int fourcc; | 56 unsigned int fourcc; |
| 57 unsigned int fourcc_mask; | 57 unsigned int fourcc_mask; |
| 58 } ifaces[] = | 58 } ifaces[] = { |
| 59 { | |
| 60 #if CONFIG_VP8_DECODER | 59 #if CONFIG_VP8_DECODER |
| 61 {"vp8", &vpx_codec_vp8_dx_algo, VP8_FOURCC, 0x00FFFFFF}, | 60 {"vp8", vpx_codec_vp8_dx, VP8_FOURCC, 0x00FFFFFF}, |
| 61 #endif |
| 62 #if CONFIG_VP9_DECODER |
| 63 {"vp9", vpx_codec_vp9_dx, VP9_FOURCC, 0x00FFFFFF}, |
| 62 #endif | 64 #endif |
| 63 }; | 65 }; |
| 64 | 66 |
| 65 #include "args.h" | 67 #include "args.h" |
| 66 static const arg_def_t codecarg = ARG_DEF(NULL, "codec", 1, | 68 static const arg_def_t codecarg = ARG_DEF(NULL, "codec", 1, |
| 67 "Codec to use"); | 69 "Codec to use"); |
| 68 static const arg_def_t use_yv12 = ARG_DEF(NULL, "yv12", 0, | 70 static const arg_def_t use_yv12 = ARG_DEF(NULL, "yv12", 0, |
| 69 "Output raw YV12 frames"); | 71 "Output raw YV12 frames"); |
| 70 static const arg_def_t use_i420 = ARG_DEF(NULL, "i420", 0, | 72 static const arg_def_t use_i420 = ARG_DEF(NULL, "i420", 0, |
| 71 "Output raw I420 frames"); | 73 "Output raw I420 frames"); |
| 72 static const arg_def_t flipuvarg = ARG_DEF(NULL, "flipuv", 0, | 74 static const arg_def_t flipuvarg = ARG_DEF(NULL, "flipuv", 0, |
| 73 "Flip the chroma planes in the output"); | 75 "Flip the chroma planes in the output
"); |
| 74 static const arg_def_t noblitarg = ARG_DEF(NULL, "noblit", 0, | 76 static const arg_def_t noblitarg = ARG_DEF(NULL, "noblit", 0, |
| 75 "Don't process the decoded frames"); | 77 "Don't process the decoded frames"); |
| 76 static const arg_def_t progressarg = ARG_DEF(NULL, "progress", 0, | 78 static const arg_def_t progressarg = ARG_DEF(NULL, "progress", 0, |
| 77 "Show progress after each frame decodes"); | 79 "Show progress after each frame dec
odes"); |
| 78 static const arg_def_t limitarg = ARG_DEF(NULL, "limit", 1, | 80 static const arg_def_t limitarg = ARG_DEF(NULL, "limit", 1, |
| 79 "Stop decoding after n frames"); | 81 "Stop decoding after n frames"); |
| 82 static const arg_def_t skiparg = ARG_DEF(NULL, "skip", 1, |
| 83 "Skip the first n input frames"); |
| 80 static const arg_def_t postprocarg = ARG_DEF(NULL, "postproc", 0, | 84 static const arg_def_t postprocarg = ARG_DEF(NULL, "postproc", 0, |
| 81 "Postprocess decoded frames"); | 85 "Postprocess decoded frames"); |
| 82 static const arg_def_t summaryarg = ARG_DEF(NULL, "summary", 0, | 86 static const arg_def_t summaryarg = ARG_DEF(NULL, "summary", 0, |
| 83 "Show timing summary"); | 87 "Show timing summary"); |
| 84 static const arg_def_t outputfile = ARG_DEF("o", "output", 1, | 88 static const arg_def_t outputfile = ARG_DEF("o", "output", 1, |
| 85 "Output file name pattern (see below)"); | 89 "Output file name pattern (see below
)"); |
| 86 static const arg_def_t threadsarg = ARG_DEF("t", "threads", 1, | 90 static const arg_def_t threadsarg = ARG_DEF("t", "threads", 1, |
| 87 "Max threads to use"); | 91 "Max threads to use"); |
| 88 static const arg_def_t verbosearg = ARG_DEF("v", "verbose", 0, | 92 static const arg_def_t verbosearg = ARG_DEF("v", "verbose", 0, |
| 89 "Show version string"); | 93 "Show version string"); |
| 90 static const arg_def_t error_concealment = ARG_DEF(NULL, "error-concealment", 0, | 94 static const arg_def_t error_concealment = ARG_DEF(NULL, "error-concealment", 0, |
| 91 "Enable decoder error-concealment"); | 95 "Enable decoder error-conceal
ment"); |
| 92 | 96 |
| 93 | 97 |
| 94 #if CONFIG_MD5 | 98 #if CONFIG_MD5 |
| 95 static const arg_def_t md5arg = ARG_DEF(NULL, "md5", 0, | 99 static const arg_def_t md5arg = ARG_DEF(NULL, "md5", 0, |
| 96 "Compute the MD5 sum of the decoded fram
e"); | 100 "Compute the MD5 sum of the decoded fram
e"); |
| 97 #endif | 101 #endif |
| 98 static const arg_def_t *all_args[] = | 102 static const arg_def_t *all_args[] = { |
| 99 { | 103 &codecarg, &use_yv12, &use_i420, &flipuvarg, &noblitarg, |
| 100 &codecarg, &use_yv12, &use_i420, &flipuvarg, &noblitarg, | 104 &progressarg, &limitarg, &skiparg, &postprocarg, &summaryarg, &outputfile, |
| 101 &progressarg, &limitarg, &postprocarg, &summaryarg, &outputfile, | 105 &threadsarg, &verbosearg, |
| 102 &threadsarg, &verbosearg, | |
| 103 #if CONFIG_MD5 | 106 #if CONFIG_MD5 |
| 104 &md5arg, | 107 &md5arg, |
| 105 #endif | 108 #endif |
| 106 &error_concealment, | 109 &error_concealment, |
| 107 NULL | 110 NULL |
| 108 }; | 111 }; |
| 109 | 112 |
| 110 #if CONFIG_VP8_DECODER | 113 #if CONFIG_VP8_DECODER |
| 111 static const arg_def_t addnoise_level = ARG_DEF(NULL, "noise-level", 1, | 114 static const arg_def_t addnoise_level = ARG_DEF(NULL, "noise-level", 1, |
| 112 "Enable VP8 postproc add noise"); | 115 "Enable VP8 postproc add noise")
; |
| 113 static const arg_def_t deblock = ARG_DEF(NULL, "deblock", 0, | 116 static const arg_def_t deblock = ARG_DEF(NULL, "deblock", 0, |
| 114 "Enable VP8 deblocking"); | 117 "Enable VP8 deblocking"); |
| 115 static const arg_def_t demacroblock_level = ARG_DEF(NULL, "demacroblock-level",
1, | 118 static const arg_def_t demacroblock_level = ARG_DEF(NULL, "demacroblock-level",
1, |
| 116 "Enable VP8 demacroblocking, w/ level"); | 119 "Enable VP8 demacroblocking,
w/ level"); |
| 117 static const arg_def_t pp_debug_info = ARG_DEF(NULL, "pp-debug-info", 1, | 120 static const arg_def_t pp_debug_info = ARG_DEF(NULL, "pp-debug-info", 1, |
| 118 "Enable VP8 visible debug info"); | 121 "Enable VP8 visible debug info"); |
| 119 static const arg_def_t pp_disp_ref_frame = ARG_DEF(NULL, "pp-dbg-ref-frame", 1, | 122 static const arg_def_t pp_disp_ref_frame = ARG_DEF(NULL, "pp-dbg-ref-frame", 1, |
| 120 "Display only selected reference frame pe
r macro block"); | 123 "Display only selected refere
nce frame per macro block"); |
| 121 static const arg_def_t pp_disp_mb_modes = ARG_DEF(NULL, "pp-dbg-mb-modes", 1, | 124 static const arg_def_t pp_disp_mb_modes = ARG_DEF(NULL, "pp-dbg-mb-modes", 1, |
| 122 "Display only selected macro block modes"
); | 125 "Display only selected macro b
lock modes"); |
| 123 static const arg_def_t pp_disp_b_modes = ARG_DEF(NULL, "pp-dbg-b-modes", 1, | 126 static const arg_def_t pp_disp_b_modes = ARG_DEF(NULL, "pp-dbg-b-modes", 1, |
| 124 "Display only selected block modes"); | 127 "Display only selected block mo
des"); |
| 125 static const arg_def_t pp_disp_mvs = ARG_DEF(NULL, "pp-dbg-mvs", 1, | 128 static const arg_def_t pp_disp_mvs = ARG_DEF(NULL, "pp-dbg-mvs", 1, |
| 126 "Draw only selected motion vectors"); | 129 "Draw only selected motion vectors"
); |
| 127 static const arg_def_t mfqe = ARG_DEF(NULL, "mfqe", 0, | 130 static const arg_def_t mfqe = ARG_DEF(NULL, "mfqe", 0, |
| 128 "Enable multiframe quality enhancement"); | 131 "Enable multiframe quality enhancement"); |
| 129 | 132 |
| 130 static const arg_def_t *vp8_pp_args[] = | 133 static const arg_def_t *vp8_pp_args[] = { |
| 131 { | 134 &addnoise_level, &deblock, &demacroblock_level, &pp_debug_info, |
| 132 &addnoise_level, &deblock, &demacroblock_level, &pp_debug_info, | 135 &pp_disp_ref_frame, &pp_disp_mb_modes, &pp_disp_b_modes, &pp_disp_mvs, &mfqe, |
| 133 &pp_disp_ref_frame, &pp_disp_mb_modes, &pp_disp_b_modes, &pp_disp_mvs, &mfqe
, | 136 NULL |
| 134 NULL | |
| 135 }; | 137 }; |
| 136 #endif | 138 #endif |
| 137 | 139 |
| 138 static void usage_exit() | 140 static void usage_exit() { |
| 139 { | 141 int i; |
| 140 int i; | |
| 141 | 142 |
| 142 fprintf(stderr, "Usage: %s <options> filename\n\n" | 143 fprintf(stderr, "Usage: %s <options> filename\n\n" |
| 143 "Options:\n", exec_name); | 144 "Options:\n", exec_name); |
| 144 arg_show_usage(stderr, all_args); | 145 arg_show_usage(stderr, all_args); |
| 145 #if CONFIG_VP8_DECODER | 146 #if CONFIG_VP8_DECODER |
| 146 fprintf(stderr, "\nVP8 Postprocessing Options:\n"); | 147 fprintf(stderr, "\nVP8 Postprocessing Options:\n"); |
| 147 arg_show_usage(stderr, vp8_pp_args); | 148 arg_show_usage(stderr, vp8_pp_args); |
| 148 #endif | 149 #endif |
| 149 fprintf(stderr, | 150 fprintf(stderr, |
| 150 "\nOutput File Patterns:\n\n" | 151 "\nOutput File Patterns:\n\n" |
| 151 " The -o argument specifies the name of the file(s) to " | 152 " The -o argument specifies the name of the file(s) to " |
| 152 "write to. If the\n argument does not include any escape " | 153 "write to. If the\n argument does not include any escape " |
| 153 "characters, the output will be\n written to a single file. " | 154 "characters, the output will be\n written to a single file. " |
| 154 "Otherwise, the filename will be calculated by\n expanding " | 155 "Otherwise, the filename will be calculated by\n expanding " |
| 155 "the following escape characters:\n"); | 156 "the following escape characters:\n"); |
| 156 fprintf(stderr, | 157 fprintf(stderr, |
| 157 "\n\t%%w - Frame width" | 158 "\n\t%%w - Frame width" |
| 158 "\n\t%%h - Frame height" | 159 "\n\t%%h - Frame height" |
| 159 "\n\t%%<n> - Frame number, zero padded to <n> places (1..9)" | 160 "\n\t%%<n> - Frame number, zero padded to <n> places (1..9)" |
| 160 "\n\n Pattern arguments are only supported in conjunction " | 161 "\n\n Pattern arguments are only supported in conjunction " |
| 161 "with the --yv12 and\n --i420 options. If the -o option is " | 162 "with the --yv12 and\n --i420 options. If the -o option is " |
| 162 "not specified, the output will be\n directed to stdout.\n" | 163 "not specified, the output will be\n directed to stdout.\n" |
| 163 ); | 164 ); |
| 164 fprintf(stderr, "\nIncluded decoders:\n\n"); | 165 fprintf(stderr, "\nIncluded decoders:\n\n"); |
| 165 | 166 |
| 166 for (i = 0; i < sizeof(ifaces) / sizeof(ifaces[0]); i++) | 167 for (i = 0; i < sizeof(ifaces) / sizeof(ifaces[0]); i++) |
| 167 fprintf(stderr, " %-6s - %s\n", | 168 fprintf(stderr, " %-6s - %s\n", |
| 168 ifaces[i].name, | 169 ifaces[i].name, |
| 169 vpx_codec_iface_name(ifaces[i].iface)); | 170 vpx_codec_iface_name(ifaces[i].iface())); |
| 170 | 171 |
| 171 exit(EXIT_FAILURE); | 172 exit(EXIT_FAILURE); |
| 172 } | 173 } |
| 173 | 174 |
| 174 void die(const char *fmt, ...) | 175 void die(const char *fmt, ...) { |
| 175 { | 176 va_list ap; |
| 176 va_list ap; | 177 va_start(ap, fmt); |
| 177 va_start(ap, fmt); | 178 vfprintf(stderr, fmt, ap); |
| 178 vfprintf(stderr, fmt, ap); | 179 fprintf(stderr, "\n"); |
| 179 fprintf(stderr, "\n"); | 180 usage_exit(); |
| 180 usage_exit(); | |
| 181 } | 181 } |
| 182 | 182 |
| 183 static unsigned int mem_get_le16(const void *vmem) | 183 static unsigned int mem_get_le16(const void *vmem) { |
| 184 { | 184 unsigned int val; |
| 185 unsigned int val; | 185 const unsigned char *mem = (const unsigned char *)vmem; |
| 186 const unsigned char *mem = (const unsigned char *)vmem; | |
| 187 | 186 |
| 188 val = mem[1] << 8; | 187 val = mem[1] << 8; |
| 189 val |= mem[0]; | 188 val |= mem[0]; |
| 190 return val; | 189 return val; |
| 191 } | 190 } |
| 192 | 191 |
| 193 static unsigned int mem_get_le32(const void *vmem) | 192 static unsigned int mem_get_le32(const void *vmem) { |
| 194 { | 193 unsigned int val; |
| 195 unsigned int val; | 194 const unsigned char *mem = (const unsigned char *)vmem; |
| 196 const unsigned char *mem = (const unsigned char *)vmem; | |
| 197 | 195 |
| 198 val = mem[3] << 24; | 196 val = mem[3] << 24; |
| 199 val |= mem[2] << 16; | 197 val |= mem[2] << 16; |
| 200 val |= mem[1] << 8; | 198 val |= mem[1] << 8; |
| 201 val |= mem[0]; | 199 val |= mem[0]; |
| 202 return val; | 200 return val; |
| 203 } | 201 } |
| 204 | 202 |
| 205 enum file_kind | 203 enum file_kind { |
| 206 { | 204 RAW_FILE, |
| 207 RAW_FILE, | 205 IVF_FILE, |
| 208 IVF_FILE, | 206 WEBM_FILE |
| 209 WEBM_FILE | |
| 210 }; | 207 }; |
| 211 | 208 |
| 212 struct input_ctx | 209 struct input_ctx { |
| 213 { | 210 enum file_kind kind; |
| 214 enum file_kind kind; | 211 FILE *infile; |
| 215 FILE *infile; | 212 nestegg *nestegg_ctx; |
| 216 nestegg *nestegg_ctx; | 213 nestegg_packet *pkt; |
| 217 nestegg_packet *pkt; | 214 unsigned int chunk; |
| 218 unsigned int chunk; | 215 unsigned int chunks; |
| 219 unsigned int chunks; | 216 unsigned int video_track; |
| 220 unsigned int video_track; | |
| 221 }; | 217 }; |
| 222 | 218 |
| 223 #define IVF_FRAME_HDR_SZ (sizeof(uint32_t) + sizeof(uint64_t)) | 219 #define IVF_FRAME_HDR_SZ (sizeof(uint32_t) + sizeof(uint64_t)) |
| 224 #define RAW_FRAME_HDR_SZ (sizeof(uint32_t)) | 220 #define RAW_FRAME_HDR_SZ (sizeof(uint32_t)) |
| 225 static int read_frame(struct input_ctx *input, | 221 static int read_frame(struct input_ctx *input, |
| 226 uint8_t **buf, | 222 uint8_t **buf, |
| 227 size_t *buf_sz, | 223 size_t *buf_sz, |
| 228 size_t *buf_alloc_sz) | 224 size_t *buf_alloc_sz) { |
| 229 { | 225 char raw_hdr[IVF_FRAME_HDR_SZ]; |
| 230 char raw_hdr[IVF_FRAME_HDR_SZ]; | 226 size_t new_buf_sz; |
| 231 size_t new_buf_sz; | 227 FILE *infile = input->infile; |
| 232 FILE *infile = input->infile; | 228 enum file_kind kind = input->kind; |
| 233 enum file_kind kind = input->kind; | 229 if (kind == WEBM_FILE) { |
| 234 if(kind == WEBM_FILE) | 230 if (input->chunk >= input->chunks) { |
| 235 { | 231 unsigned int track; |
| 236 if(input->chunk >= input->chunks) | |
| 237 { | |
| 238 unsigned int track; | |
| 239 | 232 |
| 240 do | 233 do { |
| 241 { | 234 /* End of this packet, get another. */ |
| 242 /* End of this packet, get another. */ | 235 if (input->pkt) |
| 243 if(input->pkt) | 236 nestegg_free_packet(input->pkt); |
| 244 nestegg_free_packet(input->pkt); | |
| 245 | 237 |
| 246 if(nestegg_read_packet(input->nestegg_ctx, &input->pkt) <= 0 | 238 if (nestegg_read_packet(input->nestegg_ctx, &input->pkt) <= 0 |
| 247 || nestegg_packet_track(input->pkt, &track)) | 239 || nestegg_packet_track(input->pkt, &track)) |
| 248 return 1; | 240 return 1; |
| 249 | 241 |
| 250 } while(track != input->video_track); | 242 } while (track != input->video_track); |
| 251 | 243 |
| 252 if(nestegg_packet_count(input->pkt, &input->chunks)) | 244 if (nestegg_packet_count(input->pkt, &input->chunks)) |
| 253 return 1; | 245 return 1; |
| 254 input->chunk = 0; | 246 input->chunk = 0; |
| 255 } | |
| 256 | |
| 257 if(nestegg_packet_data(input->pkt, input->chunk, buf, buf_sz)) | |
| 258 return 1; | |
| 259 input->chunk++; | |
| 260 | |
| 261 return 0; | |
| 262 } | |
| 263 /* For both the raw and ivf formats, the frame size is the first 4 bytes | |
| 264 * of the frame header. We just need to special case on the header | |
| 265 * size. | |
| 266 */ | |
| 267 else if (fread(raw_hdr, kind==IVF_FILE | |
| 268 ? IVF_FRAME_HDR_SZ : RAW_FRAME_HDR_SZ, 1, infile) != 1) | |
| 269 { | |
| 270 if (!feof(infile)) | |
| 271 fprintf(stderr, "Failed to read frame size\n"); | |
| 272 | |
| 273 new_buf_sz = 0; | |
| 274 } | |
| 275 else | |
| 276 { | |
| 277 new_buf_sz = mem_get_le32(raw_hdr); | |
| 278 | |
| 279 if (new_buf_sz > 256 * 1024 * 1024) | |
| 280 { | |
| 281 fprintf(stderr, "Error: Read invalid frame size (%u)\n", | |
| 282 (unsigned int)new_buf_sz); | |
| 283 new_buf_sz = 0; | |
| 284 } | |
| 285 | |
| 286 if (kind == RAW_FILE && new_buf_sz > 256 * 1024) | |
| 287 fprintf(stderr, "Warning: Read invalid frame size (%u)" | |
| 288 " - not a raw file?\n", (unsigned int)new_buf_sz); | |
| 289 | |
| 290 if (new_buf_sz > *buf_alloc_sz) | |
| 291 { | |
| 292 uint8_t *new_buf = realloc(*buf, 2 * new_buf_sz); | |
| 293 | |
| 294 if (new_buf) | |
| 295 { | |
| 296 *buf = new_buf; | |
| 297 *buf_alloc_sz = 2 * new_buf_sz; | |
| 298 } | |
| 299 else | |
| 300 { | |
| 301 fprintf(stderr, "Failed to allocate compressed data buffer\n"); | |
| 302 new_buf_sz = 0; | |
| 303 } | |
| 304 } | |
| 305 } | 247 } |
| 306 | 248 |
| 307 *buf_sz = new_buf_sz; | 249 if (nestegg_packet_data(input->pkt, input->chunk, buf, buf_sz)) |
| 250 return 1; |
| 251 input->chunk++; |
| 308 | 252 |
| 253 return 0; |
| 254 } |
| 255 /* For both the raw and ivf formats, the frame size is the first 4 bytes |
| 256 * of the frame header. We just need to special case on the header |
| 257 * size. |
| 258 */ |
| 259 else if (fread(raw_hdr, kind == IVF_FILE |
| 260 ? IVF_FRAME_HDR_SZ : RAW_FRAME_HDR_SZ, 1, infile) != 1) { |
| 309 if (!feof(infile)) | 261 if (!feof(infile)) |
| 310 { | 262 fprintf(stderr, "Failed to read frame size\n"); |
| 311 if (fread(*buf, 1, *buf_sz, infile) != *buf_sz) | |
| 312 { | |
| 313 fprintf(stderr, "Failed to read full frame\n"); | |
| 314 return 1; | |
| 315 } | |
| 316 | 263 |
| 317 return 0; | 264 new_buf_sz = 0; |
| 265 } else { |
| 266 new_buf_sz = mem_get_le32(raw_hdr); |
| 267 |
| 268 if (new_buf_sz > 256 * 1024 * 1024) { |
| 269 fprintf(stderr, "Error: Read invalid frame size (%u)\n", |
| 270 (unsigned int)new_buf_sz); |
| 271 new_buf_sz = 0; |
| 318 } | 272 } |
| 319 | 273 |
| 320 return 1; | 274 if (kind == RAW_FILE && new_buf_sz > 256 * 1024) |
| 275 fprintf(stderr, "Warning: Read invalid frame size (%u)" |
| 276 " - not a raw file?\n", (unsigned int)new_buf_sz); |
| 277 |
| 278 if (new_buf_sz > *buf_alloc_sz) { |
| 279 uint8_t *new_buf = realloc(*buf, 2 * new_buf_sz); |
| 280 |
| 281 if (new_buf) { |
| 282 *buf = new_buf; |
| 283 *buf_alloc_sz = 2 * new_buf_sz; |
| 284 } else { |
| 285 fprintf(stderr, "Failed to allocate compressed data buffer\n"); |
| 286 new_buf_sz = 0; |
| 287 } |
| 288 } |
| 289 } |
| 290 |
| 291 *buf_sz = new_buf_sz; |
| 292 |
| 293 if (!feof(infile)) { |
| 294 if (fread(*buf, 1, *buf_sz, infile) != *buf_sz) { |
| 295 fprintf(stderr, "Failed to read full frame\n"); |
| 296 return 1; |
| 297 } |
| 298 |
| 299 return 0; |
| 300 } |
| 301 |
| 302 return 1; |
| 321 } | 303 } |
| 322 | 304 |
| 323 void *out_open(const char *out_fn, int do_md5) | 305 void *out_open(const char *out_fn, int do_md5) { |
| 324 { | 306 void *out = NULL; |
| 325 void *out = NULL; | |
| 326 | 307 |
| 327 if (do_md5) | 308 if (do_md5) { |
| 328 { | |
| 329 #if CONFIG_MD5 | 309 #if CONFIG_MD5 |
| 330 MD5Context *md5_ctx = out = malloc(sizeof(MD5Context)); | 310 MD5Context *md5_ctx = out = malloc(sizeof(MD5Context)); |
| 331 (void)out_fn; | 311 (void)out_fn; |
| 332 MD5Init(md5_ctx); | 312 MD5Init(md5_ctx); |
| 333 #endif | 313 #endif |
| 314 } else { |
| 315 FILE *outfile = out = strcmp("-", out_fn) ? fopen(out_fn, "wb") |
| 316 : set_binary_mode(stdout); |
| 317 |
| 318 if (!outfile) { |
| 319 fprintf(stderr, "Failed to output file"); |
| 320 exit(EXIT_FAILURE); |
| 334 } | 321 } |
| 335 else | 322 } |
| 336 { | |
| 337 FILE *outfile = out = strcmp("-", out_fn) ? fopen(out_fn, "wb") | |
| 338 : set_binary_mode(stdout); | |
| 339 | 323 |
| 340 if (!outfile) | 324 return out; |
| 341 { | |
| 342 fprintf(stderr, "Failed to output file"); | |
| 343 exit(EXIT_FAILURE); | |
| 344 } | |
| 345 } | |
| 346 | |
| 347 return out; | |
| 348 } | 325 } |
| 349 | 326 |
| 350 void out_put(void *out, const uint8_t *buf, unsigned int len, int do_md5) | 327 void out_put(void *out, const uint8_t *buf, unsigned int len, int do_md5) { |
| 351 { | 328 if (do_md5) { |
| 352 if (do_md5) | |
| 353 { | |
| 354 #if CONFIG_MD5 | 329 #if CONFIG_MD5 |
| 355 MD5Update(out, buf, len); | 330 MD5Update(out, buf, len); |
| 356 #endif | 331 #endif |
| 357 } | 332 } else { |
| 358 else | 333 (void) fwrite(buf, 1, len, out); |
| 359 { | 334 } |
| 360 (void) fwrite(buf, 1, len, out); | |
| 361 } | |
| 362 } | 335 } |
| 363 | 336 |
| 364 void out_close(void *out, const char *out_fn, int do_md5) | 337 void out_close(void *out, const char *out_fn, int do_md5) { |
| 365 { | 338 if (do_md5) { |
| 366 if (do_md5) | |
| 367 { | |
| 368 #if CONFIG_MD5 | 339 #if CONFIG_MD5 |
| 369 uint8_t md5[16]; | 340 uint8_t md5[16]; |
| 370 int i; | 341 int i; |
| 371 | 342 |
| 372 MD5Final(md5, out); | 343 MD5Final(md5, out); |
| 373 free(out); | 344 free(out); |
| 374 | 345 |
| 375 for (i = 0; i < 16; i++) | 346 for (i = 0; i < 16; i++) |
| 376 printf("%02x", md5[i]); | 347 printf("%02x", md5[i]); |
| 377 | 348 |
| 378 printf(" %s\n", out_fn); | 349 printf(" %s\n", out_fn); |
| 379 #endif | 350 #endif |
| 380 } | 351 } else { |
| 381 else | 352 fclose(out); |
| 382 { | 353 } |
| 383 fclose(out); | |
| 384 } | |
| 385 } | 354 } |
| 386 | 355 |
| 387 unsigned int file_is_ivf(FILE *infile, | 356 unsigned int file_is_ivf(FILE *infile, |
| 388 unsigned int *fourcc, | 357 unsigned int *fourcc, |
| 389 unsigned int *width, | 358 unsigned int *width, |
| 390 unsigned int *height, | 359 unsigned int *height, |
| 391 unsigned int *fps_den, | 360 unsigned int *fps_den, |
| 392 unsigned int *fps_num) | 361 unsigned int *fps_num) { |
| 393 { | 362 char raw_hdr[32]; |
| 394 char raw_hdr[32]; | 363 int is_ivf = 0; |
| 395 int is_ivf = 0; | |
| 396 | 364 |
| 397 if (fread(raw_hdr, 1, 32, infile) == 32) | 365 if (fread(raw_hdr, 1, 32, infile) == 32) { |
| 398 { | 366 if (raw_hdr[0] == 'D' && raw_hdr[1] == 'K' |
| 399 if (raw_hdr[0] == 'D' && raw_hdr[1] == 'K' | 367 && raw_hdr[2] == 'I' && raw_hdr[3] == 'F') { |
| 400 && raw_hdr[2] == 'I' && raw_hdr[3] == 'F') | 368 is_ivf = 1; |
| 401 { | |
| 402 is_ivf = 1; | |
| 403 | 369 |
| 404 if (mem_get_le16(raw_hdr + 4) != 0) | 370 if (mem_get_le16(raw_hdr + 4) != 0) |
| 405 fprintf(stderr, "Error: Unrecognized IVF version! This file may
not" | 371 fprintf(stderr, "Error: Unrecognized IVF version! This file may not" |
| 406 " decode properly."); | 372 " decode properly."); |
| 407 | 373 |
| 408 *fourcc = mem_get_le32(raw_hdr + 8); | 374 *fourcc = mem_get_le32(raw_hdr + 8); |
| 409 *width = mem_get_le16(raw_hdr + 12); | 375 *width = mem_get_le16(raw_hdr + 12); |
| 410 *height = mem_get_le16(raw_hdr + 14); | 376 *height = mem_get_le16(raw_hdr + 14); |
| 411 *fps_num = mem_get_le32(raw_hdr + 16); | 377 *fps_num = mem_get_le32(raw_hdr + 16); |
| 412 *fps_den = mem_get_le32(raw_hdr + 20); | 378 *fps_den = mem_get_le32(raw_hdr + 20); |
| 413 | 379 |
| 414 /* Some versions of vpxenc used 1/(2*fps) for the timebase, so | 380 /* Some versions of vpxenc used 1/(2*fps) for the timebase, so |
| 415 * we can guess the framerate using only the timebase in this | 381 * we can guess the framerate using only the timebase in this |
| 416 * case. Other files would require reading ahead to guess the | 382 * case. Other files would require reading ahead to guess the |
| 417 * timebase, like we do for webm. | 383 * timebase, like we do for webm. |
| 418 */ | 384 */ |
| 419 if(*fps_num < 1000) | 385 if (*fps_num < 1000) { |
| 420 { | 386 /* Correct for the factor of 2 applied to the timebase in the |
| 421 /* Correct for the factor of 2 applied to the timebase in the | 387 * encoder. |
| 422 * encoder. | 388 */ |
| 423 */ | 389 if (*fps_num & 1)*fps_den <<= 1; |
| 424 if(*fps_num&1)*fps_den<<=1; | 390 else *fps_num >>= 1; |
| 425 else *fps_num>>=1; | 391 } else { |
| 426 } | 392 /* Don't know FPS for sure, and don't have readahead code |
| 427 else | 393 * (yet?), so just default to 30fps. |
| 428 { | 394 */ |
| 429 /* Don't know FPS for sure, and don't have readahead code | 395 *fps_num = 30; |
| 430 * (yet?), so just default to 30fps. | 396 *fps_den = 1; |
| 431 */ | 397 } |
| 432 *fps_num = 30; | |
| 433 *fps_den = 1; | |
| 434 } | |
| 435 } | |
| 436 } | 398 } |
| 399 } |
| 437 | 400 |
| 438 if (!is_ivf) | 401 if (!is_ivf) |
| 439 rewind(infile); | 402 rewind(infile); |
| 440 | 403 |
| 441 return is_ivf; | 404 return is_ivf; |
| 442 } | 405 } |
| 443 | 406 |
| 444 | 407 |
| 445 unsigned int file_is_raw(FILE *infile, | 408 unsigned int file_is_raw(FILE *infile, |
| 446 unsigned int *fourcc, | 409 unsigned int *fourcc, |
| 447 unsigned int *width, | 410 unsigned int *width, |
| 448 unsigned int *height, | 411 unsigned int *height, |
| 449 unsigned int *fps_den, | 412 unsigned int *fps_den, |
| 450 unsigned int *fps_num) | 413 unsigned int *fps_num) { |
| 451 { | 414 unsigned char buf[32]; |
| 452 unsigned char buf[32]; | 415 int is_raw = 0; |
| 453 int is_raw = 0; | 416 vpx_codec_stream_info_t si; |
| 454 vpx_codec_stream_info_t si; | |
| 455 | 417 |
| 456 si.sz = sizeof(si); | 418 si.sz = sizeof(si); |
| 457 | 419 |
| 458 if (fread(buf, 1, 32, infile) == 32) | 420 if (fread(buf, 1, 32, infile) == 32) { |
| 459 { | 421 int i; |
| 460 int i; | |
| 461 | 422 |
| 462 if(mem_get_le32(buf) < 256 * 1024 * 1024) | 423 if (mem_get_le32(buf) < 256 * 1024 * 1024) |
| 463 for (i = 0; i < sizeof(ifaces) / sizeof(ifaces[0]); i++) | 424 for (i = 0; i < sizeof(ifaces) / sizeof(ifaces[0]); i++) |
| 464 if(!vpx_codec_peek_stream_info(ifaces[i].iface, | 425 if (!vpx_codec_peek_stream_info(ifaces[i].iface(), |
| 465 buf + 4, 32 - 4, &si)) | 426 buf + 4, 32 - 4, &si)) { |
| 466 { | 427 is_raw = 1; |
| 467 is_raw = 1; | 428 *fourcc = ifaces[i].fourcc; |
| 468 *fourcc = ifaces[i].fourcc; | 429 *width = si.w; |
| 469 *width = si.w; | 430 *height = si.h; |
| 470 *height = si.h; | 431 *fps_num = 30; |
| 471 *fps_num = 30; | 432 *fps_den = 1; |
| 472 *fps_den = 1; | 433 break; |
| 473 break; | 434 } |
| 474 } | 435 } |
| 475 } | |
| 476 | 436 |
| 477 rewind(infile); | 437 rewind(infile); |
| 478 return is_raw; | 438 return is_raw; |
| 479 } | 439 } |
| 480 | 440 |
| 481 | 441 |
| 482 static int | 442 static int |
| 483 nestegg_read_cb(void *buffer, size_t length, void *userdata) | 443 nestegg_read_cb(void *buffer, size_t length, void *userdata) { |
| 484 { | 444 FILE *f = userdata; |
| 485 FILE *f = userdata; | |
| 486 | 445 |
| 487 if(fread(buffer, 1, length, f) < length) | 446 if (fread(buffer, 1, length, f) < length) { |
| 488 { | 447 if (ferror(f)) |
| 489 if (ferror(f)) | 448 return -1; |
| 490 return -1; | 449 if (feof(f)) |
| 491 if (feof(f)) | 450 return 0; |
| 492 return 0; | 451 } |
| 493 } | 452 return 1; |
| 494 return 1; | |
| 495 } | 453 } |
| 496 | 454 |
| 497 | 455 |
| 498 static int | 456 static int |
| 499 nestegg_seek_cb(int64_t offset, int whence, void * userdata) | 457 nestegg_seek_cb(int64_t offset, int whence, void *userdata) { |
| 500 { | 458 switch (whence) { |
| 501 switch(whence) { | 459 case NESTEGG_SEEK_SET: |
| 502 case NESTEGG_SEEK_SET: whence = SEEK_SET; break; | 460 whence = SEEK_SET; |
| 503 case NESTEGG_SEEK_CUR: whence = SEEK_CUR; break; | 461 break; |
| 504 case NESTEGG_SEEK_END: whence = SEEK_END; break; | 462 case NESTEGG_SEEK_CUR: |
| 505 }; | 463 whence = SEEK_CUR; |
| 506 return fseek(userdata, (long)offset, whence)? -1 : 0; | 464 break; |
| 465 case NESTEGG_SEEK_END: |
| 466 whence = SEEK_END; |
| 467 break; |
| 468 }; |
| 469 return fseek(userdata, (long)offset, whence) ? -1 : 0; |
| 507 } | 470 } |
| 508 | 471 |
| 509 | 472 |
| 510 static int64_t | 473 static int64_t |
| 511 nestegg_tell_cb(void * userdata) | 474 nestegg_tell_cb(void *userdata) { |
| 512 { | 475 return ftell(userdata); |
| 513 return ftell(userdata); | |
| 514 } | 476 } |
| 515 | 477 |
| 516 | 478 |
| 517 static void | 479 static void |
| 518 nestegg_log_cb(nestegg * context, unsigned int severity, char const * format, | 480 nestegg_log_cb(nestegg *context, unsigned int severity, char const *format, |
| 519 ...) | 481 ...) { |
| 520 { | 482 va_list ap; |
| 521 va_list ap; | |
| 522 | 483 |
| 523 va_start(ap, format); | 484 va_start(ap, format); |
| 524 vfprintf(stderr, format, ap); | 485 vfprintf(stderr, format, ap); |
| 525 fprintf(stderr, "\n"); | 486 fprintf(stderr, "\n"); |
| 526 va_end(ap); | 487 va_end(ap); |
| 527 } | 488 } |
| 528 | 489 |
| 529 | 490 |
| 530 static int | 491 static int |
| 531 webm_guess_framerate(struct input_ctx *input, | 492 webm_guess_framerate(struct input_ctx *input, |
| 532 unsigned int *fps_den, | 493 unsigned int *fps_den, |
| 533 unsigned int *fps_num) | 494 unsigned int *fps_num) { |
| 534 { | 495 unsigned int i; |
| 535 unsigned int i; | 496 uint64_t tstamp = 0; |
| 536 uint64_t tstamp=0; | |
| 537 | 497 |
| 538 /* Guess the framerate. Read up to 1 second, or 50 video packets, | 498 /* Guess the framerate. Read up to 1 second, or 50 video packets, |
| 539 * whichever comes first. | 499 * whichever comes first. |
| 540 */ | 500 */ |
| 541 for(i=0; tstamp < 1000000000 && i < 50;) | 501 for (i = 0; tstamp < 1000000000 && i < 50;) { |
| 542 { | 502 nestegg_packet *pkt; |
| 543 nestegg_packet * pkt; | 503 unsigned int track; |
| 544 unsigned int track; | |
| 545 | 504 |
| 546 if(nestegg_read_packet(input->nestegg_ctx, &pkt) <= 0) | 505 if (nestegg_read_packet(input->nestegg_ctx, &pkt) <= 0) |
| 547 break; | 506 break; |
| 548 | 507 |
| 549 nestegg_packet_track(pkt, &track); | 508 nestegg_packet_track(pkt, &track); |
| 550 if(track == input->video_track) | 509 if (track == input->video_track) { |
| 551 { | 510 nestegg_packet_tstamp(pkt, &tstamp); |
| 552 nestegg_packet_tstamp(pkt, &tstamp); | 511 i++; |
| 553 i++; | |
| 554 } | |
| 555 | |
| 556 nestegg_free_packet(pkt); | |
| 557 } | 512 } |
| 558 | 513 |
| 559 if(nestegg_track_seek(input->nestegg_ctx, input->video_track, 0)) | 514 nestegg_free_packet(pkt); |
| 560 goto fail; | 515 } |
| 561 | 516 |
| 562 *fps_num = (i - 1) * 1000000; | 517 if (nestegg_track_seek(input->nestegg_ctx, input->video_track, 0)) |
| 563 *fps_den = (unsigned int)(tstamp / 1000); | 518 goto fail; |
| 564 return 0; | 519 |
| 520 *fps_num = (i - 1) * 1000000; |
| 521 *fps_den = (unsigned int)(tstamp / 1000); |
| 522 return 0; |
| 565 fail: | 523 fail: |
| 566 nestegg_destroy(input->nestegg_ctx); | 524 nestegg_destroy(input->nestegg_ctx); |
| 567 input->nestegg_ctx = NULL; | 525 input->nestegg_ctx = NULL; |
| 568 rewind(input->infile); | 526 rewind(input->infile); |
| 569 return 1; | 527 return 1; |
| 570 } | 528 } |
| 571 | 529 |
| 572 | 530 |
| 573 static int | 531 static int |
| 574 file_is_webm(struct input_ctx *input, | 532 file_is_webm(struct input_ctx *input, |
| 575 unsigned int *fourcc, | 533 unsigned int *fourcc, |
| 576 unsigned int *width, | 534 unsigned int *width, |
| 577 unsigned int *height, | 535 unsigned int *height, |
| 578 unsigned int *fps_den, | 536 unsigned int *fps_den, |
| 579 unsigned int *fps_num) | 537 unsigned int *fps_num) { |
| 580 { | 538 unsigned int i, n; |
| 581 unsigned int i, n; | 539 int track_type = -1; |
| 582 int track_type = -1; | 540 int codec_id; |
| 583 | 541 |
| 584 nestegg_io io = {nestegg_read_cb, nestegg_seek_cb, nestegg_tell_cb, 0}; | 542 nestegg_io io = {nestegg_read_cb, nestegg_seek_cb, nestegg_tell_cb, 0}; |
| 585 nestegg_video_params params; | 543 nestegg_video_params params; |
| 586 | 544 |
| 587 io.userdata = input->infile; | 545 io.userdata = input->infile; |
| 588 if(nestegg_init(&input->nestegg_ctx, io, NULL)) | 546 if (nestegg_init(&input->nestegg_ctx, io, NULL)) |
| 589 goto fail; | 547 goto fail; |
| 590 | 548 |
| 591 if(nestegg_track_count(input->nestegg_ctx, &n)) | 549 if (nestegg_track_count(input->nestegg_ctx, &n)) |
| 592 goto fail; | 550 goto fail; |
| 593 | 551 |
| 594 for(i=0; i<n; i++) | 552 for (i = 0; i < n; i++) { |
| 595 { | 553 track_type = nestegg_track_type(input->nestegg_ctx, i); |
| 596 track_type = nestegg_track_type(input->nestegg_ctx, i); | 554 |
| 597 | 555 if (track_type == NESTEGG_TRACK_VIDEO) |
| 598 if(track_type == NESTEGG_TRACK_VIDEO) | 556 break; |
| 599 break; | 557 else if (track_type < 0) |
| 600 else if(track_type < 0) | 558 goto fail; |
| 601 goto fail; | 559 } |
| 602 } | 560 |
| 603 | 561 codec_id = nestegg_track_codec_id(input->nestegg_ctx, i); |
| 604 if(nestegg_track_codec_id(input->nestegg_ctx, i) != NESTEGG_CODEC_VP8) | 562 if (codec_id == NESTEGG_CODEC_VP8) { |
| 605 { | |
| 606 fprintf(stderr, "Not VP8 video, quitting.\n"); | |
| 607 exit(1); | |
| 608 } | |
| 609 | |
| 610 input->video_track = i; | |
| 611 | |
| 612 if(nestegg_track_video_params(input->nestegg_ctx, i, ¶ms)) | |
| 613 goto fail; | |
| 614 | |
| 615 *fps_den = 0; | |
| 616 *fps_num = 0; | |
| 617 *fourcc = VP8_FOURCC; | 563 *fourcc = VP8_FOURCC; |
| 618 *width = params.width; | 564 } else if (codec_id == NESTEGG_CODEC_VP9) { |
| 619 *height = params.height; | 565 *fourcc = VP9_FOURCC; |
| 620 return 1; | 566 } else { |
| 567 fprintf(stderr, "Not VPx video, quitting.\n"); |
| 568 exit(1); |
| 569 } |
| 570 |
| 571 input->video_track = i; |
| 572 |
| 573 if (nestegg_track_video_params(input->nestegg_ctx, i, ¶ms)) |
| 574 goto fail; |
| 575 |
| 576 *fps_den = 0; |
| 577 *fps_num = 0; |
| 578 *width = params.width; |
| 579 *height = params.height; |
| 580 return 1; |
| 621 fail: | 581 fail: |
| 622 input->nestegg_ctx = NULL; | 582 input->nestegg_ctx = NULL; |
| 623 rewind(input->infile); | 583 rewind(input->infile); |
| 624 return 0; | 584 return 0; |
| 625 } | 585 } |
| 626 | 586 |
| 627 | 587 |
| 628 void show_progress(int frame_in, int frame_out, unsigned long dx_time) | 588 void show_progress(int frame_in, int frame_out, unsigned long dx_time) { |
| 629 { | 589 fprintf(stderr, "%d decoded frames/%d showed frames in %lu us (%.2f fps)\r", |
| 630 fprintf(stderr, "%d decoded frames/%d showed frames in %lu us (%.2f fps)\r", | 590 frame_in, frame_out, dx_time, |
| 631 frame_in, frame_out, dx_time, | 591 (float)frame_out * 1000000.0 / (float)dx_time); |
| 632 (float)frame_out * 1000000.0 / (float)dx_time); | |
| 633 } | 592 } |
| 634 | 593 |
| 635 | 594 |
| 636 void generate_filename(const char *pattern, char *out, size_t q_len, | 595 void generate_filename(const char *pattern, char *out, size_t q_len, |
| 637 unsigned int d_w, unsigned int d_h, | 596 unsigned int d_w, unsigned int d_h, |
| 638 unsigned int frame_in) | 597 unsigned int frame_in) { |
| 639 { | 598 const char *p = pattern; |
| 640 const char *p = pattern; | 599 char *q = out; |
| 641 char *q = out; | 600 |
| 642 | 601 do { |
| 643 do | 602 char *next_pat = strchr(p, '%'); |
| 644 { | 603 |
| 645 char *next_pat = strchr(p, '%'); | 604 if (p == next_pat) { |
| 646 | 605 size_t pat_len; |
| 647 if(p == next_pat) | 606 |
| 648 { | 607 /* parse the pattern */ |
| 649 size_t pat_len; | 608 q[q_len - 1] = '\0'; |
| 650 | 609 switch (p[1]) { |
| 651 /* parse the pattern */ | 610 case 'w': |
| 652 q[q_len - 1] = '\0'; | 611 snprintf(q, q_len - 1, "%d", d_w); |
| 653 switch(p[1]) | 612 break; |
| 654 { | 613 case 'h': |
| 655 case 'w': snprintf(q, q_len - 1, "%d", d_w); break; | 614 snprintf(q, q_len - 1, "%d", d_h); |
| 656 case 'h': snprintf(q, q_len - 1, "%d", d_h); break; | 615 break; |
| 657 case '1': snprintf(q, q_len - 1, "%d", frame_in); break; | 616 case '1': |
| 658 case '2': snprintf(q, q_len - 1, "%02d", frame_in); break; | 617 snprintf(q, q_len - 1, "%d", frame_in); |
| 659 case '3': snprintf(q, q_len - 1, "%03d", frame_in); break; | 618 break; |
| 660 case '4': snprintf(q, q_len - 1, "%04d", frame_in); break; | 619 case '2': |
| 661 case '5': snprintf(q, q_len - 1, "%05d", frame_in); break; | 620 snprintf(q, q_len - 1, "%02d", frame_in); |
| 662 case '6': snprintf(q, q_len - 1, "%06d", frame_in); break; | 621 break; |
| 663 case '7': snprintf(q, q_len - 1, "%07d", frame_in); break; | 622 case '3': |
| 664 case '8': snprintf(q, q_len - 1, "%08d", frame_in); break; | 623 snprintf(q, q_len - 1, "%03d", frame_in); |
| 665 case '9': snprintf(q, q_len - 1, "%09d", frame_in); break; | 624 break; |
| 666 default: | 625 case '4': |
| 667 die("Unrecognized pattern %%%c\n", p[1]); | 626 snprintf(q, q_len - 1, "%04d", frame_in); |
| 668 } | 627 break; |
| 669 | 628 case '5': |
| 670 pat_len = strlen(q); | 629 snprintf(q, q_len - 1, "%05d", frame_in); |
| 671 if(pat_len >= q_len - 1) | 630 break; |
| 672 die("Output filename too long.\n"); | 631 case '6': |
| 673 q += pat_len; | 632 snprintf(q, q_len - 1, "%06d", frame_in); |
| 674 p += 2; | 633 break; |
| 675 q_len -= pat_len; | 634 case '7': |
| 635 snprintf(q, q_len - 1, "%07d", frame_in); |
| 636 break; |
| 637 case '8': |
| 638 snprintf(q, q_len - 1, "%08d", frame_in); |
| 639 break; |
| 640 case '9': |
| 641 snprintf(q, q_len - 1, "%09d", frame_in); |
| 642 break; |
| 643 default: |
| 644 die("Unrecognized pattern %%%c\n", p[1]); |
| 645 } |
| 646 |
| 647 pat_len = strlen(q); |
| 648 if (pat_len >= q_len - 1) |
| 649 die("Output filename too long.\n"); |
| 650 q += pat_len; |
| 651 p += 2; |
| 652 q_len -= pat_len; |
| 653 } else { |
| 654 size_t copy_len; |
| 655 |
| 656 /* copy the next segment */ |
| 657 if (!next_pat) |
| 658 copy_len = strlen(p); |
| 659 else |
| 660 copy_len = next_pat - p; |
| 661 |
| 662 if (copy_len >= q_len - 1) |
| 663 die("Output filename too long.\n"); |
| 664 |
| 665 memcpy(q, p, copy_len); |
| 666 q[copy_len] = '\0'; |
| 667 q += copy_len; |
| 668 p += copy_len; |
| 669 q_len -= copy_len; |
| 670 } |
| 671 } while (*p); |
| 672 } |
| 673 |
| 674 |
| 675 int main(int argc, const char **argv_) { |
| 676 vpx_codec_ctx_t decoder; |
| 677 char *fn = NULL; |
| 678 int i; |
| 679 uint8_t *buf = NULL; |
| 680 size_t buf_sz = 0, buf_alloc_sz = 0; |
| 681 FILE *infile; |
| 682 int frame_in = 0, frame_out = 0, flipuv = 0, noblit = 0, do
_md5 = 0, progress = 0; |
| 683 int stop_after = 0, postproc = 0, summary = 0, quiet = 1; |
| 684 int arg_skip = 0; |
| 685 int ec_enabled = 0; |
| 686 vpx_codec_iface_t *iface = NULL; |
| 687 unsigned int fourcc; |
| 688 unsigned long dx_time = 0; |
| 689 struct arg arg; |
| 690 char **argv, **argi, **argj; |
| 691 const char *outfile_pattern = 0; |
| 692 char outfile[PATH_MAX]; |
| 693 int single_file; |
| 694 int use_y4m = 1; |
| 695 unsigned int width; |
| 696 unsigned int height; |
| 697 unsigned int fps_den; |
| 698 unsigned int fps_num; |
| 699 void *out = NULL; |
| 700 vpx_codec_dec_cfg_t cfg = {0}; |
| 701 #if CONFIG_VP8_DECODER |
| 702 vp8_postproc_cfg_t vp8_pp_cfg = {0}; |
| 703 int vp8_dbg_color_ref_frame = 0; |
| 704 int vp8_dbg_color_mb_modes = 0; |
| 705 int vp8_dbg_color_b_modes = 0; |
| 706 int vp8_dbg_display_mv = 0; |
| 707 #endif |
| 708 struct input_ctx input = {0}; |
| 709 int frames_corrupted = 0; |
| 710 int dec_flags = 0; |
| 711 |
| 712 /* Parse command line */ |
| 713 exec_name = argv_[0]; |
| 714 argv = argv_dup(argc - 1, argv_ + 1); |
| 715 |
| 716 for (argi = argj = argv; (*argj = *argi); argi += arg.argv_step) { |
| 717 memset(&arg, 0, sizeof(arg)); |
| 718 arg.argv_step = 1; |
| 719 |
| 720 if (arg_match(&arg, &codecarg, argi)) { |
| 721 int j, k = -1; |
| 722 |
| 723 for (j = 0; j < sizeof(ifaces) / sizeof(ifaces[0]); j++) |
| 724 if (!strcmp(ifaces[j].name, arg.val)) |
| 725 k = j; |
| 726 |
| 727 if (k >= 0) |
| 728 iface = ifaces[k].iface(); |
| 729 else |
| 730 die("Error: Unrecognized argument (%s) to --codec\n", |
| 731 arg.val); |
| 732 } else if (arg_match(&arg, &outputfile, argi)) |
| 733 outfile_pattern = arg.val; |
| 734 else if (arg_match(&arg, &use_yv12, argi)) { |
| 735 use_y4m = 0; |
| 736 flipuv = 1; |
| 737 } else if (arg_match(&arg, &use_i420, argi)) { |
| 738 use_y4m = 0; |
| 739 flipuv = 0; |
| 740 } else if (arg_match(&arg, &flipuvarg, argi)) |
| 741 flipuv = 1; |
| 742 else if (arg_match(&arg, &noblitarg, argi)) |
| 743 noblit = 1; |
| 744 else if (arg_match(&arg, &progressarg, argi)) |
| 745 progress = 1; |
| 746 else if (arg_match(&arg, &limitarg, argi)) |
| 747 stop_after = arg_parse_uint(&arg); |
| 748 else if (arg_match(&arg, &skiparg, argi)) |
| 749 arg_skip = arg_parse_uint(&arg); |
| 750 else if (arg_match(&arg, &postprocarg, argi)) |
| 751 postproc = 1; |
| 752 else if (arg_match(&arg, &md5arg, argi)) |
| 753 do_md5 = 1; |
| 754 else if (arg_match(&arg, &summaryarg, argi)) |
| 755 summary = 1; |
| 756 else if (arg_match(&arg, &threadsarg, argi)) |
| 757 cfg.threads = arg_parse_uint(&arg); |
| 758 else if (arg_match(&arg, &verbosearg, argi)) |
| 759 quiet = 0; |
| 760 |
| 761 #if CONFIG_VP8_DECODER |
| 762 else if (arg_match(&arg, &addnoise_level, argi)) { |
| 763 postproc = 1; |
| 764 vp8_pp_cfg.post_proc_flag |= VP8_ADDNOISE; |
| 765 vp8_pp_cfg.noise_level = arg_parse_uint(&arg); |
| 766 } else if (arg_match(&arg, &demacroblock_level, argi)) { |
| 767 postproc = 1; |
| 768 vp8_pp_cfg.post_proc_flag |= VP8_DEMACROBLOCK; |
| 769 vp8_pp_cfg.deblocking_level = arg_parse_uint(&arg); |
| 770 } else if (arg_match(&arg, &deblock, argi)) { |
| 771 postproc = 1; |
| 772 vp8_pp_cfg.post_proc_flag |= VP8_DEBLOCK; |
| 773 } else if (arg_match(&arg, &mfqe, argi)) { |
| 774 postproc = 1; |
| 775 vp8_pp_cfg.post_proc_flag |= VP8_MFQE; |
| 776 } else if (arg_match(&arg, &pp_debug_info, argi)) { |
| 777 unsigned int level = arg_parse_uint(&arg); |
| 778 |
| 779 postproc = 1; |
| 780 vp8_pp_cfg.post_proc_flag &= ~0x7; |
| 781 |
| 782 if (level) |
| 783 vp8_pp_cfg.post_proc_flag |= level; |
| 784 } else if (arg_match(&arg, &pp_disp_ref_frame, argi)) { |
| 785 unsigned int flags = arg_parse_int(&arg); |
| 786 if (flags) { |
| 787 postproc = 1; |
| 788 vp8_dbg_color_ref_frame = flags; |
| 789 } |
| 790 } else if (arg_match(&arg, &pp_disp_mb_modes, argi)) { |
| 791 unsigned int flags = arg_parse_int(&arg); |
| 792 if (flags) { |
| 793 postproc = 1; |
| 794 vp8_dbg_color_mb_modes = flags; |
| 795 } |
| 796 } else if (arg_match(&arg, &pp_disp_b_modes, argi)) { |
| 797 unsigned int flags = arg_parse_int(&arg); |
| 798 if (flags) { |
| 799 postproc = 1; |
| 800 vp8_dbg_color_b_modes = flags; |
| 801 } |
| 802 } else if (arg_match(&arg, &pp_disp_mvs, argi)) { |
| 803 unsigned int flags = arg_parse_int(&arg); |
| 804 if (flags) { |
| 805 postproc = 1; |
| 806 vp8_dbg_display_mv = flags; |
| 807 } |
| 808 } else if (arg_match(&arg, &error_concealment, argi)) { |
| 809 ec_enabled = 1; |
| 810 } |
| 811 |
| 812 #endif |
| 813 else |
| 814 argj++; |
| 815 } |
| 816 |
| 817 /* Check for unrecognized options */ |
| 818 for (argi = argv; *argi; argi++) |
| 819 if (argi[0][0] == '-' && strlen(argi[0]) > 1) |
| 820 die("Error: Unrecognized option %s\n", *argi); |
| 821 |
| 822 /* Handle non-option arguments */ |
| 823 fn = argv[0]; |
| 824 |
| 825 if (!fn) |
| 826 usage_exit(); |
| 827 |
| 828 /* Open file */ |
| 829 infile = strcmp(fn, "-") ? fopen(fn, "rb") : set_binary_mode(stdin); |
| 830 |
| 831 if (!infile) { |
| 832 fprintf(stderr, "Failed to open file '%s'", |
| 833 strcmp(fn, "-") ? fn : "stdin"); |
| 834 return EXIT_FAILURE; |
| 835 } |
| 836 #if CONFIG_OS_SUPPORT |
| 837 /* Make sure we don't dump to the terminal, unless forced to with -o - */ |
| 838 if (!outfile_pattern && isatty(fileno(stdout)) && !do_md5 && !noblit) { |
| 839 fprintf(stderr, |
| 840 "Not dumping raw video to your terminal. Use '-o -' to " |
| 841 "override.\n"); |
| 842 return EXIT_FAILURE; |
| 843 } |
| 844 #endif |
| 845 input.infile = infile; |
| 846 if (file_is_ivf(infile, &fourcc, &width, &height, &fps_den, |
| 847 &fps_num)) |
| 848 input.kind = IVF_FILE; |
| 849 else if (file_is_webm(&input, &fourcc, &width, &height, &fps_den, &fps_num)) |
| 850 input.kind = WEBM_FILE; |
| 851 else if (file_is_raw(infile, &fourcc, &width, &height, &fps_den, &fps_num)) |
| 852 input.kind = RAW_FILE; |
| 853 else { |
| 854 fprintf(stderr, "Unrecognized input file type.\n"); |
| 855 return EXIT_FAILURE; |
| 856 } |
| 857 |
| 858 /* If the output file is not set or doesn't have a sequence number in |
| 859 * it, then we only open it once. |
| 860 */ |
| 861 outfile_pattern = outfile_pattern ? outfile_pattern : "-"; |
| 862 single_file = 1; |
| 863 { |
| 864 const char *p = outfile_pattern; |
| 865 do { |
| 866 p = strchr(p, '%'); |
| 867 if (p && p[1] >= '1' && p[1] <= '9') { |
| 868 /* pattern contains sequence number, so it's not unique. */ |
| 869 single_file = 0; |
| 870 break; |
| 871 } |
| 872 if (p) |
| 873 p++; |
| 874 } while (p); |
| 875 } |
| 876 |
| 877 if (single_file && !noblit) { |
| 878 generate_filename(outfile_pattern, outfile, sizeof(outfile) - 1, |
| 879 width, height, 0); |
| 880 out = out_open(outfile, do_md5); |
| 881 } |
| 882 |
| 883 if (use_y4m && !noblit) { |
| 884 char buffer[128]; |
| 885 if (!single_file) { |
| 886 fprintf(stderr, "YUV4MPEG2 not supported with output patterns," |
| 887 " try --i420 or --yv12.\n"); |
| 888 return EXIT_FAILURE; |
| 889 } |
| 890 |
| 891 if (input.kind == WEBM_FILE) |
| 892 if (webm_guess_framerate(&input, &fps_den, &fps_num)) { |
| 893 fprintf(stderr, "Failed to guess framerate -- error parsing " |
| 894 "webm file?\n"); |
| 895 return EXIT_FAILURE; |
| 896 } |
| 897 |
| 898 |
| 899 /*Note: We can't output an aspect ratio here because IVF doesn't |
| 900 store one, and neither does VP8. |
| 901 That will have to wait until these tools support WebM natively.*/ |
| 902 sprintf(buffer, "YUV4MPEG2 C%s W%u H%u F%u:%u I%c\n", |
| 903 "420jpeg", width, height, fps_num, fps_den, 'p'); |
| 904 out_put(out, (unsigned char *)buffer, |
| 905 (unsigned int)strlen(buffer), do_md5); |
| 906 } |
| 907 |
| 908 /* Try to determine the codec from the fourcc. */ |
| 909 for (i = 0; i < sizeof(ifaces) / sizeof(ifaces[0]); i++) |
| 910 if ((fourcc & ifaces[i].fourcc_mask) == ifaces[i].fourcc) { |
| 911 vpx_codec_iface_t *ivf_iface = ifaces[i].iface(); |
| 912 |
| 913 if (iface && iface != ivf_iface) |
| 914 fprintf(stderr, "Notice -- IVF header indicates codec: %s\n", |
| 915 ifaces[i].name); |
| 916 else |
| 917 iface = ivf_iface; |
| 918 |
| 919 break; |
| 920 } |
| 921 |
| 922 dec_flags = (postproc ? VPX_CODEC_USE_POSTPROC : 0) | |
| 923 (ec_enabled ? VPX_CODEC_USE_ERROR_CONCEALMENT : 0); |
| 924 if (vpx_codec_dec_init(&decoder, iface ? iface : ifaces[0].iface(), &cfg, |
| 925 dec_flags)) { |
| 926 fprintf(stderr, "Failed to initialize decoder: %s\n", vpx_codec_error(&decod
er)); |
| 927 return EXIT_FAILURE; |
| 928 } |
| 929 |
| 930 if (!quiet) |
| 931 fprintf(stderr, "%s\n", decoder.name); |
| 932 |
| 933 #if CONFIG_VP8_DECODER |
| 934 |
| 935 if (vp8_pp_cfg.post_proc_flag |
| 936 && vpx_codec_control(&decoder, VP8_SET_POSTPROC, &vp8_pp_cfg)) { |
| 937 fprintf(stderr, "Failed to configure postproc: %s\n", vpx_codec_error(&decod
er)); |
| 938 return EXIT_FAILURE; |
| 939 } |
| 940 |
| 941 if (vp8_dbg_color_ref_frame |
| 942 && vpx_codec_control(&decoder, VP8_SET_DBG_COLOR_REF_FRAME, vp8_dbg_color_
ref_frame)) { |
| 943 fprintf(stderr, "Failed to configure reference block visualizer: %s\n", vpx_
codec_error(&decoder)); |
| 944 return EXIT_FAILURE; |
| 945 } |
| 946 |
| 947 if (vp8_dbg_color_mb_modes |
| 948 && vpx_codec_control(&decoder, VP8_SET_DBG_COLOR_MB_MODES, vp8_dbg_color_m
b_modes)) { |
| 949 fprintf(stderr, "Failed to configure macro block visualizer: %s\n", vpx_code
c_error(&decoder)); |
| 950 return EXIT_FAILURE; |
| 951 } |
| 952 |
| 953 if (vp8_dbg_color_b_modes |
| 954 && vpx_codec_control(&decoder, VP8_SET_DBG_COLOR_B_MODES, vp8_dbg_color_b_
modes)) { |
| 955 fprintf(stderr, "Failed to configure block visualizer: %s\n", vpx_codec_erro
r(&decoder)); |
| 956 return EXIT_FAILURE; |
| 957 } |
| 958 |
| 959 if (vp8_dbg_display_mv |
| 960 && vpx_codec_control(&decoder, VP8_SET_DBG_DISPLAY_MV, vp8_dbg_display_mv)
) { |
| 961 fprintf(stderr, "Failed to configure motion vector visualizer: %s\n", vpx_co
dec_error(&decoder)); |
| 962 return EXIT_FAILURE; |
| 963 } |
| 964 #endif |
| 965 |
| 966 |
| 967 if(arg_skip) |
| 968 fprintf(stderr, "Skiping first %d frames.\n", arg_skip); |
| 969 while (arg_skip) { |
| 970 if (read_frame(&input, &buf, &buf_sz, &buf_alloc_sz)) |
| 971 break; |
| 972 arg_skip--; |
| 973 } |
| 974 |
| 975 /* Decode file */ |
| 976 while (!read_frame(&input, &buf, &buf_sz, &buf_alloc_sz)) { |
| 977 vpx_codec_iter_t iter = NULL; |
| 978 vpx_image_t *img; |
| 979 struct vpx_usec_timer timer; |
| 980 int corrupted; |
| 981 |
| 982 vpx_usec_timer_start(&timer); |
| 983 |
| 984 if (vpx_codec_decode(&decoder, buf, (unsigned int)buf_sz, NULL, 0)) { |
| 985 const char *detail = vpx_codec_error_detail(&decoder); |
| 986 fprintf(stderr, "Failed to decode frame: %s\n", vpx_codec_error(&decoder))
; |
| 987 |
| 988 if (detail) |
| 989 fprintf(stderr, " Additional information: %s\n", detail); |
| 990 |
| 991 goto fail; |
| 992 } |
| 993 |
| 994 vpx_usec_timer_mark(&timer); |
| 995 dx_time += (unsigned int)vpx_usec_timer_elapsed(&timer); |
| 996 |
| 997 ++frame_in; |
| 998 |
| 999 if (vpx_codec_control(&decoder, VP8D_GET_FRAME_CORRUPTED, &corrupted)) { |
| 1000 fprintf(stderr, "Failed VP8_GET_FRAME_CORRUPTED: %s\n", |
| 1001 vpx_codec_error(&decoder)); |
| 1002 goto fail; |
| 1003 } |
| 1004 frames_corrupted += corrupted; |
| 1005 |
| 1006 vpx_usec_timer_start(&timer); |
| 1007 |
| 1008 if ((img = vpx_codec_get_frame(&decoder, &iter))) |
| 1009 ++frame_out; |
| 1010 |
| 1011 vpx_usec_timer_mark(&timer); |
| 1012 dx_time += (unsigned int)vpx_usec_timer_elapsed(&timer); |
| 1013 |
| 1014 if (progress) |
| 1015 show_progress(frame_in, frame_out, dx_time); |
| 1016 |
| 1017 if (!noblit) { |
| 1018 if (img) { |
| 1019 unsigned int y; |
| 1020 char out_fn[PATH_MAX]; |
| 1021 uint8_t *buf; |
| 1022 |
| 1023 if (!single_file) { |
| 1024 size_t len = sizeof(out_fn) - 1; |
| 1025 |
| 1026 out_fn[len] = '\0'; |
| 1027 generate_filename(outfile_pattern, out_fn, len - 1, |
| 1028 img->d_w, img->d_h, frame_in); |
| 1029 out = out_open(out_fn, do_md5); |
| 1030 } else if (use_y4m) |
| 1031 out_put(out, (unsigned char *)"FRAME\n", 6, do_md5); |
| 1032 |
| 1033 buf = img->planes[VPX_PLANE_Y]; |
| 1034 |
| 1035 for (y = 0; y < img->d_h; y++) { |
| 1036 out_put(out, buf, img->d_w, do_md5); |
| 1037 buf += img->stride[VPX_PLANE_Y]; |
| 676 } | 1038 } |
| 677 else | 1039 |
| 678 { | 1040 buf = img->planes[flipuv ? VPX_PLANE_V : VPX_PLANE_U]; |
| 679 size_t copy_len; | 1041 |
| 680 | 1042 for (y = 0; y < (1 + img->d_h) / 2; y++) { |
| 681 /* copy the next segment */ | 1043 out_put(out, buf, (1 + img->d_w) / 2, do_md5); |
| 682 if(!next_pat) | 1044 buf += img->stride[VPX_PLANE_U]; |
| 683 copy_len = strlen(p); | |
| 684 else | |
| 685 copy_len = next_pat - p; | |
| 686 | |
| 687 if(copy_len >= q_len - 1) | |
| 688 die("Output filename too long.\n"); | |
| 689 | |
| 690 memcpy(q, p, copy_len); | |
| 691 q[copy_len] = '\0'; | |
| 692 q += copy_len; | |
| 693 p += copy_len; | |
| 694 q_len -= copy_len; | |
| 695 } | 1045 } |
| 696 } while(*p); | 1046 |
| 1047 buf = img->planes[flipuv ? VPX_PLANE_U : VPX_PLANE_V]; |
| 1048 |
| 1049 for (y = 0; y < (1 + img->d_h) / 2; y++) { |
| 1050 out_put(out, buf, (1 + img->d_w) / 2, do_md5); |
| 1051 buf += img->stride[VPX_PLANE_V]; |
| 1052 } |
| 1053 |
| 1054 if (!single_file) |
| 1055 out_close(out, out_fn, do_md5); |
| 1056 } |
| 1057 } |
| 1058 |
| 1059 if (stop_after && frame_in >= stop_after) |
| 1060 break; |
| 1061 } |
| 1062 |
| 1063 if (summary || progress) { |
| 1064 show_progress(frame_in, frame_out, dx_time); |
| 1065 fprintf(stderr, "\n"); |
| 1066 } |
| 1067 |
| 1068 if (frames_corrupted) |
| 1069 fprintf(stderr, "WARNING: %d frames corrupted.\n", frames_corrupted); |
| 1070 |
| 1071 fail: |
| 1072 |
| 1073 if (vpx_codec_destroy(&decoder)) { |
| 1074 fprintf(stderr, "Failed to destroy decoder: %s\n", vpx_codec_error(&decoder)
); |
| 1075 return EXIT_FAILURE; |
| 1076 } |
| 1077 |
| 1078 if (single_file && !noblit) |
| 1079 out_close(out, outfile, do_md5); |
| 1080 |
| 1081 if (input.nestegg_ctx) |
| 1082 nestegg_destroy(input.nestegg_ctx); |
| 1083 if (input.kind != WEBM_FILE) |
| 1084 free(buf); |
| 1085 fclose(infile); |
| 1086 free(argv); |
| 1087 |
| 1088 return frames_corrupted ? EXIT_FAILURE : EXIT_SUCCESS; |
| 697 } | 1089 } |
| 698 | |
| 699 | |
| 700 int main(int argc, const char **argv_) | |
| 701 { | |
| 702 vpx_codec_ctx_t decoder; | |
| 703 char *fn = NULL; | |
| 704 int i; | |
| 705 uint8_t *buf = NULL; | |
| 706 size_t buf_sz = 0, buf_alloc_sz = 0; | |
| 707 FILE *infile; | |
| 708 int frame_in = 0, frame_out = 0, flipuv = 0, noblit = 0,
do_md5 = 0, progress = 0; | |
| 709 int stop_after = 0, postproc = 0, summary = 0, quiet = 1; | |
| 710 int ec_enabled = 0; | |
| 711 vpx_codec_iface_t *iface = NULL; | |
| 712 unsigned int fourcc; | |
| 713 unsigned long dx_time = 0; | |
| 714 struct arg arg; | |
| 715 char **argv, **argi, **argj; | |
| 716 const char *outfile_pattern = 0; | |
| 717 char outfile[PATH_MAX]; | |
| 718 int single_file; | |
| 719 int use_y4m = 1; | |
| 720 unsigned int width; | |
| 721 unsigned int height; | |
| 722 unsigned int fps_den; | |
| 723 unsigned int fps_num; | |
| 724 void *out = NULL; | |
| 725 vpx_codec_dec_cfg_t cfg = {0}; | |
| 726 #if CONFIG_VP8_DECODER | |
| 727 vp8_postproc_cfg_t vp8_pp_cfg = {0}; | |
| 728 int vp8_dbg_color_ref_frame = 0; | |
| 729 int vp8_dbg_color_mb_modes = 0; | |
| 730 int vp8_dbg_color_b_modes = 0; | |
| 731 int vp8_dbg_display_mv = 0; | |
| 732 #endif | |
| 733 struct input_ctx input = {0}; | |
| 734 int frames_corrupted = 0; | |
| 735 int dec_flags = 0; | |
| 736 | |
| 737 /* Parse command line */ | |
| 738 exec_name = argv_[0]; | |
| 739 argv = argv_dup(argc - 1, argv_ + 1); | |
| 740 | |
| 741 for (argi = argj = argv; (*argj = *argi); argi += arg.argv_step) | |
| 742 { | |
| 743 memset(&arg, 0, sizeof(arg)); | |
| 744 arg.argv_step = 1; | |
| 745 | |
| 746 if (arg_match(&arg, &codecarg, argi)) | |
| 747 { | |
| 748 int j, k = -1; | |
| 749 | |
| 750 for (j = 0; j < sizeof(ifaces) / sizeof(ifaces[0]); j++) | |
| 751 if (!strcmp(ifaces[j].name, arg.val)) | |
| 752 k = j; | |
| 753 | |
| 754 if (k >= 0) | |
| 755 iface = ifaces[k].iface; | |
| 756 else | |
| 757 die("Error: Unrecognized argument (%s) to --codec\n", | |
| 758 arg.val); | |
| 759 } | |
| 760 else if (arg_match(&arg, &outputfile, argi)) | |
| 761 outfile_pattern = arg.val; | |
| 762 else if (arg_match(&arg, &use_yv12, argi)) | |
| 763 { | |
| 764 use_y4m = 0; | |
| 765 flipuv = 1; | |
| 766 } | |
| 767 else if (arg_match(&arg, &use_i420, argi)) | |
| 768 { | |
| 769 use_y4m = 0; | |
| 770 flipuv = 0; | |
| 771 } | |
| 772 else if (arg_match(&arg, &flipuvarg, argi)) | |
| 773 flipuv = 1; | |
| 774 else if (arg_match(&arg, &noblitarg, argi)) | |
| 775 noblit = 1; | |
| 776 else if (arg_match(&arg, &progressarg, argi)) | |
| 777 progress = 1; | |
| 778 else if (arg_match(&arg, &limitarg, argi)) | |
| 779 stop_after = arg_parse_uint(&arg); | |
| 780 else if (arg_match(&arg, &postprocarg, argi)) | |
| 781 postproc = 1; | |
| 782 else if (arg_match(&arg, &md5arg, argi)) | |
| 783 do_md5 = 1; | |
| 784 else if (arg_match(&arg, &summaryarg, argi)) | |
| 785 summary = 1; | |
| 786 else if (arg_match(&arg, &threadsarg, argi)) | |
| 787 cfg.threads = arg_parse_uint(&arg); | |
| 788 else if (arg_match(&arg, &verbosearg, argi)) | |
| 789 quiet = 0; | |
| 790 | |
| 791 #if CONFIG_VP8_DECODER | |
| 792 else if (arg_match(&arg, &addnoise_level, argi)) | |
| 793 { | |
| 794 postproc = 1; | |
| 795 vp8_pp_cfg.post_proc_flag |= VP8_ADDNOISE; | |
| 796 vp8_pp_cfg.noise_level = arg_parse_uint(&arg); | |
| 797 } | |
| 798 else if (arg_match(&arg, &demacroblock_level, argi)) | |
| 799 { | |
| 800 postproc = 1; | |
| 801 vp8_pp_cfg.post_proc_flag |= VP8_DEMACROBLOCK; | |
| 802 vp8_pp_cfg.deblocking_level = arg_parse_uint(&arg); | |
| 803 } | |
| 804 else if (arg_match(&arg, &deblock, argi)) | |
| 805 { | |
| 806 postproc = 1; | |
| 807 vp8_pp_cfg.post_proc_flag |= VP8_DEBLOCK; | |
| 808 } | |
| 809 else if (arg_match(&arg, &mfqe, argi)) | |
| 810 { | |
| 811 postproc = 1; | |
| 812 vp8_pp_cfg.post_proc_flag |= VP8_MFQE; | |
| 813 } | |
| 814 else if (arg_match(&arg, &pp_debug_info, argi)) | |
| 815 { | |
| 816 unsigned int level = arg_parse_uint(&arg); | |
| 817 | |
| 818 postproc = 1; | |
| 819 vp8_pp_cfg.post_proc_flag &= ~0x7; | |
| 820 | |
| 821 if (level) | |
| 822 vp8_pp_cfg.post_proc_flag |= level; | |
| 823 } | |
| 824 else if (arg_match(&arg, &pp_disp_ref_frame, argi)) | |
| 825 { | |
| 826 unsigned int flags = arg_parse_int(&arg); | |
| 827 if (flags) | |
| 828 { | |
| 829 postproc = 1; | |
| 830 vp8_dbg_color_ref_frame = flags; | |
| 831 } | |
| 832 } | |
| 833 else if (arg_match(&arg, &pp_disp_mb_modes, argi)) | |
| 834 { | |
| 835 unsigned int flags = arg_parse_int(&arg); | |
| 836 if (flags) | |
| 837 { | |
| 838 postproc = 1; | |
| 839 vp8_dbg_color_mb_modes = flags; | |
| 840 } | |
| 841 } | |
| 842 else if (arg_match(&arg, &pp_disp_b_modes, argi)) | |
| 843 { | |
| 844 unsigned int flags = arg_parse_int(&arg); | |
| 845 if (flags) | |
| 846 { | |
| 847 postproc = 1; | |
| 848 vp8_dbg_color_b_modes = flags; | |
| 849 } | |
| 850 } | |
| 851 else if (arg_match(&arg, &pp_disp_mvs, argi)) | |
| 852 { | |
| 853 unsigned int flags = arg_parse_int(&arg); | |
| 854 if (flags) | |
| 855 { | |
| 856 postproc = 1; | |
| 857 vp8_dbg_display_mv = flags; | |
| 858 } | |
| 859 } | |
| 860 else if (arg_match(&arg, &error_concealment, argi)) | |
| 861 { | |
| 862 ec_enabled = 1; | |
| 863 } | |
| 864 | |
| 865 #endif | |
| 866 else | |
| 867 argj++; | |
| 868 } | |
| 869 | |
| 870 /* Check for unrecognized options */ | |
| 871 for (argi = argv; *argi; argi++) | |
| 872 if (argi[0][0] == '-' && strlen(argi[0]) > 1) | |
| 873 die("Error: Unrecognized option %s\n", *argi); | |
| 874 | |
| 875 /* Handle non-option arguments */ | |
| 876 fn = argv[0]; | |
| 877 | |
| 878 if (!fn) | |
| 879 usage_exit(); | |
| 880 | |
| 881 /* Open file */ | |
| 882 infile = strcmp(fn, "-") ? fopen(fn, "rb") : set_binary_mode(stdin); | |
| 883 | |
| 884 if (!infile) | |
| 885 { | |
| 886 fprintf(stderr, "Failed to open file '%s'", | |
| 887 strcmp(fn, "-") ? fn : "stdin"); | |
| 888 return EXIT_FAILURE; | |
| 889 } | |
| 890 #if CONFIG_OS_SUPPORT | |
| 891 /* Make sure we don't dump to the terminal, unless forced to with -o - */ | |
| 892 if(!outfile_pattern && isatty(fileno(stdout)) && !do_md5 && !noblit) | |
| 893 { | |
| 894 fprintf(stderr, | |
| 895 "Not dumping raw video to your terminal. Use '-o -' to " | |
| 896 "override.\n"); | |
| 897 return EXIT_FAILURE; | |
| 898 } | |
| 899 #endif | |
| 900 input.infile = infile; | |
| 901 if(file_is_ivf(infile, &fourcc, &width, &height, &fps_den, | |
| 902 &fps_num)) | |
| 903 input.kind = IVF_FILE; | |
| 904 else if(file_is_webm(&input, &fourcc, &width, &height, &fps_den, &fps_num)) | |
| 905 input.kind = WEBM_FILE; | |
| 906 else if(file_is_raw(infile, &fourcc, &width, &height, &fps_den, &fps_num)) | |
| 907 input.kind = RAW_FILE; | |
| 908 else | |
| 909 { | |
| 910 fprintf(stderr, "Unrecognized input file type.\n"); | |
| 911 return EXIT_FAILURE; | |
| 912 } | |
| 913 | |
| 914 /* If the output file is not set or doesn't have a sequence number in | |
| 915 * it, then we only open it once. | |
| 916 */ | |
| 917 outfile_pattern = outfile_pattern ? outfile_pattern : "-"; | |
| 918 single_file = 1; | |
| 919 { | |
| 920 const char *p = outfile_pattern; | |
| 921 do | |
| 922 { | |
| 923 p = strchr(p, '%'); | |
| 924 if(p && p[1] >= '1' && p[1] <= '9') | |
| 925 { | |
| 926 /* pattern contains sequence number, so it's not unique. */ | |
| 927 single_file = 0; | |
| 928 break; | |
| 929 } | |
| 930 if(p) | |
| 931 p++; | |
| 932 } while(p); | |
| 933 } | |
| 934 | |
| 935 if(single_file && !noblit) | |
| 936 { | |
| 937 generate_filename(outfile_pattern, outfile, sizeof(outfile)-1, | |
| 938 width, height, 0); | |
| 939 out = out_open(outfile, do_md5); | |
| 940 } | |
| 941 | |
| 942 if (use_y4m && !noblit) | |
| 943 { | |
| 944 char buffer[128]; | |
| 945 if (!single_file) | |
| 946 { | |
| 947 fprintf(stderr, "YUV4MPEG2 not supported with output patterns," | |
| 948 " try --i420 or --yv12.\n"); | |
| 949 return EXIT_FAILURE; | |
| 950 } | |
| 951 | |
| 952 if(input.kind == WEBM_FILE) | |
| 953 if(webm_guess_framerate(&input, &fps_den, &fps_num)) | |
| 954 { | |
| 955 fprintf(stderr, "Failed to guess framerate -- error parsing " | |
| 956 "webm file?\n"); | |
| 957 return EXIT_FAILURE; | |
| 958 } | |
| 959 | |
| 960 | |
| 961 /*Note: We can't output an aspect ratio here because IVF doesn't | |
| 962 store one, and neither does VP8. | |
| 963 That will have to wait until these tools support WebM natively.*/ | |
| 964 sprintf(buffer, "YUV4MPEG2 C%s W%u H%u F%u:%u I%c\n", | |
| 965 "420jpeg", width, height, fps_num, fps_den, 'p'); | |
| 966 out_put(out, (unsigned char *)buffer, | |
| 967 (unsigned int)strlen(buffer), do_md5); | |
| 968 } | |
| 969 | |
| 970 /* Try to determine the codec from the fourcc. */ | |
| 971 for (i = 0; i < sizeof(ifaces) / sizeof(ifaces[0]); i++) | |
| 972 if ((fourcc & ifaces[i].fourcc_mask) == ifaces[i].fourcc) | |
| 973 { | |
| 974 vpx_codec_iface_t *ivf_iface = ifaces[i].iface; | |
| 975 | |
| 976 if (iface && iface != ivf_iface) | |
| 977 fprintf(stderr, "Notice -- IVF header indicates codec: %s\n", | |
| 978 ifaces[i].name); | |
| 979 else | |
| 980 iface = ivf_iface; | |
| 981 | |
| 982 break; | |
| 983 } | |
| 984 | |
| 985 dec_flags = (postproc ? VPX_CODEC_USE_POSTPROC : 0) | | |
| 986 (ec_enabled ? VPX_CODEC_USE_ERROR_CONCEALMENT : 0); | |
| 987 if (vpx_codec_dec_init(&decoder, iface ? iface : ifaces[0].iface, &cfg, | |
| 988 dec_flags)) | |
| 989 { | |
| 990 fprintf(stderr, "Failed to initialize decoder: %s\n", vpx_codec_error(&d
ecoder)); | |
| 991 return EXIT_FAILURE; | |
| 992 } | |
| 993 | |
| 994 if (!quiet) | |
| 995 fprintf(stderr, "%s\n", decoder.name); | |
| 996 | |
| 997 #if CONFIG_VP8_DECODER | |
| 998 | |
| 999 if (vp8_pp_cfg.post_proc_flag | |
| 1000 && vpx_codec_control(&decoder, VP8_SET_POSTPROC, &vp8_pp_cfg)) | |
| 1001 { | |
| 1002 fprintf(stderr, "Failed to configure postproc: %s\n", vpx_codec_error(&d
ecoder)); | |
| 1003 return EXIT_FAILURE; | |
| 1004 } | |
| 1005 | |
| 1006 if (vp8_dbg_color_ref_frame | |
| 1007 && vpx_codec_control(&decoder, VP8_SET_DBG_COLOR_REF_FRAME, vp8_dbg_colo
r_ref_frame)) | |
| 1008 { | |
| 1009 fprintf(stderr, "Failed to configure reference block visualizer: %s\n",
vpx_codec_error(&decoder)); | |
| 1010 return EXIT_FAILURE; | |
| 1011 } | |
| 1012 | |
| 1013 if (vp8_dbg_color_mb_modes | |
| 1014 && vpx_codec_control(&decoder, VP8_SET_DBG_COLOR_MB_MODES, vp8_dbg_color
_mb_modes)) | |
| 1015 { | |
| 1016 fprintf(stderr, "Failed to configure macro block visualizer: %s\n", vpx_
codec_error(&decoder)); | |
| 1017 return EXIT_FAILURE; | |
| 1018 } | |
| 1019 | |
| 1020 if (vp8_dbg_color_b_modes | |
| 1021 && vpx_codec_control(&decoder, VP8_SET_DBG_COLOR_B_MODES, vp8_dbg_color_
b_modes)) | |
| 1022 { | |
| 1023 fprintf(stderr, "Failed to configure block visualizer: %s\n", vpx_codec_
error(&decoder)); | |
| 1024 return EXIT_FAILURE; | |
| 1025 } | |
| 1026 | |
| 1027 if (vp8_dbg_display_mv | |
| 1028 && vpx_codec_control(&decoder, VP8_SET_DBG_DISPLAY_MV, vp8_dbg_display_m
v)) | |
| 1029 { | |
| 1030 fprintf(stderr, "Failed to configure motion vector visualizer: %s\n", vp
x_codec_error(&decoder)); | |
| 1031 return EXIT_FAILURE; | |
| 1032 } | |
| 1033 #endif | |
| 1034 | |
| 1035 /* Decode file */ | |
| 1036 while (!read_frame(&input, &buf, &buf_sz, &buf_alloc_sz)) | |
| 1037 { | |
| 1038 vpx_codec_iter_t iter = NULL; | |
| 1039 vpx_image_t *img; | |
| 1040 struct vpx_usec_timer timer; | |
| 1041 int corrupted; | |
| 1042 | |
| 1043 vpx_usec_timer_start(&timer); | |
| 1044 | |
| 1045 if (vpx_codec_decode(&decoder, buf, (unsigned int)buf_sz, NULL, 0)) | |
| 1046 { | |
| 1047 const char *detail = vpx_codec_error_detail(&decoder); | |
| 1048 fprintf(stderr, "Failed to decode frame: %s\n", vpx_codec_error(&dec
oder)); | |
| 1049 | |
| 1050 if (detail) | |
| 1051 fprintf(stderr, " Additional information: %s\n", detail); | |
| 1052 | |
| 1053 goto fail; | |
| 1054 } | |
| 1055 | |
| 1056 vpx_usec_timer_mark(&timer); | |
| 1057 dx_time += (unsigned int)vpx_usec_timer_elapsed(&timer); | |
| 1058 | |
| 1059 ++frame_in; | |
| 1060 | |
| 1061 if (vpx_codec_control(&decoder, VP8D_GET_FRAME_CORRUPTED, &corrupted)) | |
| 1062 { | |
| 1063 fprintf(stderr, "Failed VP8_GET_FRAME_CORRUPTED: %s\n", | |
| 1064 vpx_codec_error(&decoder)); | |
| 1065 goto fail; | |
| 1066 } | |
| 1067 frames_corrupted += corrupted; | |
| 1068 | |
| 1069 vpx_usec_timer_start(&timer); | |
| 1070 | |
| 1071 if ((img = vpx_codec_get_frame(&decoder, &iter))) | |
| 1072 ++frame_out; | |
| 1073 | |
| 1074 vpx_usec_timer_mark(&timer); | |
| 1075 dx_time += (unsigned int)vpx_usec_timer_elapsed(&timer); | |
| 1076 | |
| 1077 if (progress) | |
| 1078 show_progress(frame_in, frame_out, dx_time); | |
| 1079 | |
| 1080 if (!noblit) | |
| 1081 { | |
| 1082 if (img) | |
| 1083 { | |
| 1084 unsigned int y; | |
| 1085 char out_fn[PATH_MAX]; | |
| 1086 uint8_t *buf; | |
| 1087 | |
| 1088 if (!single_file) | |
| 1089 { | |
| 1090 size_t len = sizeof(out_fn)-1; | |
| 1091 | |
| 1092 out_fn[len] = '\0'; | |
| 1093 generate_filename(outfile_pattern, out_fn, len-1, | |
| 1094 img->d_w, img->d_h, frame_in); | |
| 1095 out = out_open(out_fn, do_md5); | |
| 1096 } | |
| 1097 else if(use_y4m) | |
| 1098 out_put(out, (unsigned char *)"FRAME\n", 6, do_md5); | |
| 1099 | |
| 1100 buf = img->planes[VPX_PLANE_Y]; | |
| 1101 | |
| 1102 for (y = 0; y < img->d_h; y++) | |
| 1103 { | |
| 1104 out_put(out, buf, img->d_w, do_md5); | |
| 1105 buf += img->stride[VPX_PLANE_Y]; | |
| 1106 } | |
| 1107 | |
| 1108 buf = img->planes[flipuv?VPX_PLANE_V:VPX_PLANE_U]; | |
| 1109 | |
| 1110 for (y = 0; y < (1 + img->d_h) / 2; y++) | |
| 1111 { | |
| 1112 out_put(out, buf, (1 + img->d_w) / 2, do_md5); | |
| 1113 buf += img->stride[VPX_PLANE_U]; | |
| 1114 } | |
| 1115 | |
| 1116 buf = img->planes[flipuv?VPX_PLANE_U:VPX_PLANE_V]; | |
| 1117 | |
| 1118 for (y = 0; y < (1 + img->d_h) / 2; y++) | |
| 1119 { | |
| 1120 out_put(out, buf, (1 + img->d_w) / 2, do_md5); | |
| 1121 buf += img->stride[VPX_PLANE_V]; | |
| 1122 } | |
| 1123 | |
| 1124 if (!single_file) | |
| 1125 out_close(out, out_fn, do_md5); | |
| 1126 } | |
| 1127 } | |
| 1128 | |
| 1129 if (stop_after && frame_in >= stop_after) | |
| 1130 break; | |
| 1131 } | |
| 1132 | |
| 1133 if (summary || progress) | |
| 1134 { | |
| 1135 show_progress(frame_in, frame_out, dx_time); | |
| 1136 fprintf(stderr, "\n"); | |
| 1137 } | |
| 1138 | |
| 1139 if (frames_corrupted) | |
| 1140 fprintf(stderr, "WARNING: %d frames corrupted.\n",frames_corrupted); | |
| 1141 | |
| 1142 fail: | |
| 1143 | |
| 1144 if (vpx_codec_destroy(&decoder)) | |
| 1145 { | |
| 1146 fprintf(stderr, "Failed to destroy decoder: %s\n", vpx_codec_error(&deco
der)); | |
| 1147 return EXIT_FAILURE; | |
| 1148 } | |
| 1149 | |
| 1150 if (single_file && !noblit) | |
| 1151 out_close(out, outfile, do_md5); | |
| 1152 | |
| 1153 if(input.nestegg_ctx) | |
| 1154 nestegg_destroy(input.nestegg_ctx); | |
| 1155 if(input.kind != WEBM_FILE) | |
| 1156 free(buf); | |
| 1157 fclose(infile); | |
| 1158 free(argv); | |
| 1159 | |
| 1160 return frames_corrupted ? EXIT_FAILURE : EXIT_SUCCESS; | |
| 1161 } | |
| OLD | NEW |