y4m_input_close(&y4m);
}
+// Testing that headers over 100 characters can be parsed.
+static const char kY4MLongHeader[] =
+ "YUV4MPEG2 W4 H4 F30:1 Ip A0:0 C420jpeg XYSCSS=420JPEG "
+ "XCOLORRANGE=LIMITED XSOME_UNKNOWN_METADATA XOTHER_UNKNOWN_METADATA\n"
+ "FRAME\n"
+ "012345678912345601230123";
+
+TEST(Y4MHeaderTest, LongHeader) {
+ libvpx_test::TempOutFile f;
+ fwrite(kY4MLongHeader, 1, sizeof(kY4MLongHeader), f.file());
+ fflush(f.file());
+ EXPECT_EQ(fseek(f.file(), 0, 0), 0);
+
+ y4m_input y4m;
+ EXPECT_EQ(y4m_input_open(&y4m, f.file(), /*skip_buffer=*/NULL,
+ /*num_skip=*/0, /*only_420=*/0),
+ 0);
+ EXPECT_EQ(y4m.pic_w, 4);
+ EXPECT_EQ(y4m.pic_h, 4);
+ EXPECT_EQ(y4m.fps_n, 30);
+ EXPECT_EQ(y4m.fps_d, 1);
+ EXPECT_EQ(y4m.interlace, 'p');
+ EXPECT_EQ(strcmp("420jpeg", y4m.chroma_type), 0);
+ y4m_input_close(&y4m);
+}
+
} // namespace
}
static int y4m_parse_tags(y4m_input *_y4m, char *_tags) {
- int got_w;
- int got_h;
- int got_fps;
- int got_interlace;
- int got_par;
- int got_chroma;
char *p;
char *q;
- got_w = got_h = got_fps = got_interlace = got_par = got_chroma = 0;
for (p = _tags;; p = q) {
/*Skip any leading spaces.*/
while (*p == ' ') p++;
switch (p[0]) {
case 'W': {
if (sscanf(p + 1, "%d", &_y4m->pic_w) != 1) return -1;
- got_w = 1;
break;
}
case 'H': {
if (sscanf(p + 1, "%d", &_y4m->pic_h) != 1) return -1;
- got_h = 1;
break;
}
case 'F': {
if (sscanf(p + 1, "%d:%d", &_y4m->fps_n, &_y4m->fps_d) != 2) {
return -1;
}
- got_fps = 1;
break;
}
case 'I': {
_y4m->interlace = p[1];
- got_interlace = 1;
break;
}
case 'A': {
if (sscanf(p + 1, "%d:%d", &_y4m->par_n, &_y4m->par_d) != 2) {
return -1;
}
- got_par = 1;
break;
}
case 'C': {
if (q - p > 16) return -1;
memcpy(_y4m->chroma_type, p + 1, q - p - 1);
_y4m->chroma_type[q - p - 1] = '\0';
- got_chroma = 1;
break;
}
/*Ignore unknown tags.*/
}
}
- if (!got_w || !got_h || !got_fps) return -1;
- if (!got_interlace) _y4m->interlace = '?';
- if (!got_par) _y4m->par_n = _y4m->par_d = 0;
- /*Chroma-type is not specified in older files, e.g., those generated by
- mplayer.*/
- if (!got_chroma) strcpy(_y4m->chroma_type, "420");
return 0;
}
+/* Returns 1 if tags were parsed successfully, 0 otherwise. */
+static int parse_tags(y4m_input *y4m_ctx, char *buffer) {
+ /* Set Y4M tags to defaults, updating them as processing occurs. Mandatory
+ fields are marked with -1 and will be checked after the tags are parsed. */
+ int ret;
+ y4m_ctx->pic_w = -1;
+ y4m_ctx->pic_h = -1;
+ y4m_ctx->fps_n = -1; /* Also serves as marker for fps_d */
+ y4m_ctx->par_n = 0;
+ y4m_ctx->par_d = 0;
+ y4m_ctx->interlace = '?';
+ snprintf(y4m_ctx->chroma_type, sizeof(y4m_ctx->chroma_type), "420");
+
+ ret = y4m_parse_tags(y4m_ctx, buffer);
+ if (ret < 0) {
+ return 0;
+ }
+
+ /* Check the mandatory fields. */
+ if (y4m_ctx->pic_w == -1) {
+ fprintf(stderr, "Width field missing\n");
+ return 0;
+ }
+ if (y4m_ctx->pic_h == -1) {
+ fprintf(stderr, "Height field missing\n");
+ return 0;
+ }
+ if (y4m_ctx->fps_n == -1) {
+ fprintf(stderr, "FPS field missing\n");
+ return 0;
+ }
+ return 1;
+}
+
/*All anti-aliasing filters in the following conversion functions are based on
one of two window functions:
The 6-tap Lanczos window (for down-sampling and shifts):
}
static const char TAG[] = "YUV4MPEG2";
+/* Temporary until arbitrary header parsing submitted. */
+#define Y4M_HEADER_BUF_SIZE 200
int y4m_input_open(y4m_input *y4m_ctx, FILE *file, char *skip_buffer,
int num_skip, int only_420) {
// File must start with |TAG|.
- char tag_buffer[9]; // 9 == strlen(TAG)
- char buffer[80] = { 0 };
- int ret;
+ char tag_buffer[9]; // 9 == strlen(TAG)
+ char buffer[Y4M_HEADER_BUF_SIZE] = { 0 }; // Rest of header.
int i;
// Read as much as possible from |skip_buffer|, which were characters
// that were previously read from the file to do input-type detection.
fprintf(stderr, "Error parsing header: space must follow %s\n", TAG);
return -1;
}
- /*Read until newline, or 80 cols, whichever happens first.*/
- for (i = 0; i < 79; i++) {
+ /*Read until newline, or Y4M_HEADER_BUF_SIZE cols, whichever happens first.*/
+ for (i = 0; i < Y4M_HEADER_BUF_SIZE - 1; i++) {
if (!file_read(buffer + i, 1, file)) return -1;
if (buffer[i] == '\n') break;
}
- /*We skipped too much header data.*/
- if (i == 79) {
- fprintf(stderr, "Error parsing header; not a YUV4MPEG2 file?\n");
+ if (i == Y4M_HEADER_BUF_SIZE - 1) {
+ fprintf(stderr, "Error parsing header; not a %s file?\n", TAG);
return -1;
}
buffer[i] = '\0';
- ret = y4m_parse_tags(y4m_ctx, buffer);
- if (ret < 0) {
- fprintf(stderr, "Error parsing YUV4MPEG2 header.\n");
- return ret;
+ if (!parse_tags(y4m_ctx, buffer)) {
+ fprintf(stderr, "Error parsing %s header.\n", TAG);
+ return -1;
}
if (y4m_ctx->interlace == '?') {
fprintf(stderr,