Previous parser assumed that the header would not exceed 80 characters. However, with latest FFMPEG changes, the header of Y4M files can exceed this limit. New parser can parse an arbitrarily long header, as long each tag is 255 or less characters. BUG=aomedia:2876
Unified · Split
| @@ -100,11 +100,50 @@ static int y4m_parse_tags(y4m_input *_y4m, char *_tags) { · 99 unmodified lines | |||
| 100 | return 0; | 100 | return 0; |
| 101 | } | 101 | } |
| 102 | 102 | ||
| 103 | // Copy a single tag into the buffer, along with a null character. | ||
| 104 | // Returns 0 if any file IO errors occur. | ||
| 105 | static int copy_tag(char *buf, size_t buf_len, char *end_tag, FILE *file) { | ||
| 106 | size_t i; | ||
| 107 | assert(buf_len >= 1); | ||
| 108 | // Skip leading space characters. | ||
| 109 | do { | ||
| 110 | if (!file_read(buf, 1, file)) { | ||
| 111 | return 0; | ||
| 112 | } | ||
| 113 | } while (buf[0] == ' '); | ||
| 114 | |||
| 115 | // If we hit the newline, treat this as the "empty" tag. | ||
| 116 | if (buf[0] == '\n') { | ||
| 117 | buf[0] = '\0'; | ||
| 118 | *end_tag = '\n'; | ||
| 119 | return 1; | ||
| 120 | } | ||
| 121 | |||
| 122 | // Copy over characters until a space is hit, or the buffer is exhausted. | ||
| 123 | for (i = 1; i < buf_len; ++i) { | ||
| 124 | if (!file_read(buf + i, 1, file)) { | ||
| 125 | return 0; | ||
| 126 | } | ||
| 127 | if (buf[i] == ' ' || buf[i] == '\n') { | ||
| 128 | break; | ||
| 129 | } | ||
| 130 | } | ||
| 131 | if (i == buf_len) { | ||
| 132 | fprintf(stderr, "Error: Y4M header tags must be less than %lu characters\n", | ||
| 133 | (unsigned long)i); | ||
| 134 | return 0; | ||
| 135 | } | ||
| 136 | *end_tag = buf[i]; | ||
| 137 | buf[i] = '\0'; | ||
| 138 | return 1; | ||
| 139 | } | ||
| 140 | |||
| 103 | /* Returns 1 if tags were parsed successfully, 0 otherwise. */ | 141 | /* Returns 1 if tags were parsed successfully, 0 otherwise. */ |
| 104 | static int parse_tags(y4m_input *y4m_ctx, char *buffer) { | 142 | static int parse_tags(y4m_input *y4m_ctx, FILE *file) { |
| 143 | char tag[256]; | ||
| 144 | char end; /* Character denoting the end of the tag, ' ' or '\n'. */ | ||
| 105 | /* Set Y4M tags to defaults, updating them as processing occurs. Mandatory | 145 | /* Set Y4M tags to defaults, updating them as processing occurs. Mandatory |
| 106 | fields are marked with -1 and will be checked after the tags are parsed. */ | 146 | fields are marked with -1 and will be checked after the tags are parsed. */ |
| 107 | int ret; | ||
| 108 | y4m_ctx->pic_w = -1; | 147 | y4m_ctx->pic_w = -1; |
| 109 | y4m_ctx->pic_h = -1; | 148 | y4m_ctx->pic_h = -1; |
| 110 | y4m_ctx->fps_n = -1; /* Also serves as marker for fps_d */ | 149 | y4m_ctx->fps_n = -1; /* Also serves as marker for fps_d */ |
| @@ -113,10 +152,16 @@ static int parse_tags(y4m_input *y4m_ctx, char *buffer) { · 2 unmodified lines | |||
| 113 | y4m_ctx->interlace = '?'; | 152 | y4m_ctx->interlace = '?'; |
| 114 | snprintf(y4m_ctx->chroma_type, sizeof(y4m_ctx->chroma_type), "420"); | 153 | snprintf(y4m_ctx->chroma_type, sizeof(y4m_ctx->chroma_type), "420"); |
| 115 | 154 | ||
| 116 | ret = y4m_parse_tags(y4m_ctx, buffer); | 155 | /* Find one tag at a time. */ |
| 117 | if (ret < 0) { | 156 | do { |
| 118 | return 0; | 157 | if (!copy_tag(tag, sizeof(tag), &end, file)) { |
| 119 | } | 158 | return 0; |
| 159 | } | ||
| 160 | /* y4m_parse_tags returns 0 on success. */ | ||
| 161 | if (y4m_parse_tags(y4m_ctx, tag)) { | ||
| 162 | return 0; | ||
| 163 | } | ||
| 164 | } while (end != '\n'); | ||
| 120 | 165 | ||
| 121 | /* Check the mandatory fields. */ | 166 | /* Check the mandatory fields. */ |
| 122 | if (y4m_ctx->pic_w == -1) { | 167 | if (y4m_ctx->pic_w == -1) { |
| @@ -801,15 +846,11 @@ static void y4m_convert_null(y4m_input *_y4m, unsigned char *_dst, · 678 unmodified lines | |||
| 801 | } | 846 | } |
| 802 | 847 | ||
| 803 | static const char TAG[] = "YUV4MPEG2"; | 848 | static const char TAG[] = "YUV4MPEG2"; |
| 804 | /* Temporary until arbitrary header parsing submitted. */ | ||
| 805 | #define Y4M_HEADER_BUF_SIZE 200 | ||
| 806 | 849 | ||
| 807 | int y4m_input_open(y4m_input *y4m_ctx, FILE *file, char *skip_buffer, | 850 | int y4m_input_open(y4m_input *y4m_ctx, FILE *file, char *skip_buffer, |
| 808 | int num_skip, int only_420) { | 851 | int num_skip, int only_420) { |
| 809 | // File must start with |TAG|. | 852 | // File must start with |TAG|. |
| 810 | char tag_buffer[9]; // 9 == strlen(TAG) | 853 | char tag_buffer[9]; // 9 == strlen(TAG) |
| 811 | char buffer[Y4M_HEADER_BUF_SIZE] = { 0 }; // Rest of header. | ||
| 812 | int i; | ||
| 813 | // Read as much as possible from |skip_buffer|, which were characters | 854 | // Read as much as possible from |skip_buffer|, which were characters |
| 814 | // that were previously read from the file to do input-type detection. | 855 | // that were previously read from the file to do input-type detection. |
| 815 | assert(num_skip >= 0 && num_skip <= 8); | 856 | assert(num_skip >= 0 && num_skip <= 8); |
| @@ -825,23 +866,12 @@ int y4m_input_open(y4m_input *y4m_ctx, FILE *file, char *skip_buffer, · 9 unmodified lines | |||
| 825 | return -1; | 866 | return -1; |
| 826 | } | 867 | } |
| 827 | // Next character must be a space. | 868 | // Next character must be a space. |
| 828 | if (!file_read(buffer, 1, file) || buffer[0] != ' ') { | 869 | if (!file_read(tag_buffer, 1, file) || tag_buffer[0] != ' ') { |
| 829 | fprintf(stderr, "Error parsing header: space must follow %s\n", TAG); | 870 | fprintf(stderr, "Error parsing header: space must follow %s\n", TAG); |
| 830 | return -1; | 871 | return -1; |
| 831 | } | 872 | } |
| 832 | /*Read until newline, or Y4M_HEADER_BUF_SIZE cols, whichever happens first.*/ | 873 | if (!parse_tags(y4m_ctx, file)) { |
| 833 | for (i = 0; i < Y4M_HEADER_BUF_SIZE - 1; i++) { | ||
| 834 | if (!file_read(buffer + i, 1, file)) return -1; | ||
| 835 | if (buffer[i] == '\n') break; | ||
| 836 | } | ||
| 837 | if (i == Y4M_HEADER_BUF_SIZE - 1) { | ||
| 838 | fprintf(stderr, "Error parsing header; not a %s file?\n", TAG); | ||
| 839 | return -1; | ||
| 840 | } | ||
| 841 | buffer[i] = '\0'; | ||
| 842 | if (!parse_tags(y4m_ctx, buffer)) { | ||
| 843 | fprintf(stderr, "Error parsing %s header.\n", TAG); | 874 | fprintf(stderr, "Error parsing %s header.\n", TAG); |
| 844 | return -1; | ||
| 845 | } | 875 | } |
| 846 | if (y4m_ctx->interlace == '?') { | 876 | if (y4m_ctx->interlace == '?') { |
| 847 | fprintf(stderr, | 877 | fprintf(stderr, |