/* * Copyright (c) 2010 The WebM project authors. All Rights Reserved. * * 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 * be found in the AUTHORS file in the root of the source tree. * * Based on code from the OggTheora software codec source code, * Copyright (C) 2002-2010 The Xiph.Org Foundation and contributors.
*/ #include <assert.h> #include <errno.h> #include <stdio.h> #include <stdlib.h> #include <string.h>
#include"vpx/vpx_integer.h" #include"y4minput.h"
// Reads 'size' bytes from 'file' into 'buf' with some fault tolerance. // Returns true on success. staticint file_read(void *buf, size_t size, FILE *file) { constint kMaxTries = 5; int try_count = 0; int file_error = 0;
size_t len = 0; while (!feof(file) && len < size && try_count < kMaxTries) { const size_t n = fread((uint8_t *)buf + len, 1, size - len, file);
++try_count;
len += n;
file_error = ferror(file); if (file_error) { if (errno == EINTR || errno == EAGAIN) {
clearerr(file); continue;
} else {
fprintf(stderr, "Error reading file: %u of %u bytes read, %d: %s\n",
(uint32_t)len, (uint32_t)size, errno, strerror(errno)); return 0;
}
}
}
if (!feof(file) && len != size) {
fprintf(stderr, "Error reading file: %u of %u bytes read," " error: %d, tries: %d, %d: %s\n",
(uint32_t)len, (uint32_t)size, file_error, try_count, errno,
strerror(errno));
} return len == size;
}
staticint y4m_parse_tags(y4m_input *_y4m, char *_tags) { char *p; char *q; for (p = _tags;; p = q) { /*Skip any leading spaces.*/ while (*p == ' ') p++; /*If that's all we have, stop.*/ if (p[0] == '\0') break; /*Find the end of this tag.*/ for (q = p + 1; *q != '\0' && *q != ' '; q++) {
} /*Process the tag.*/ switch (p[0]) { case'W': { if (sscanf(p + 1, "%d", &_y4m->pic_w) != 1) return -1; break;
} case'H': { if (sscanf(p + 1, "%d", &_y4m->pic_h) != 1) return -1; break;
} case'F': { if (sscanf(p + 1, "%d:%d", &_y4m->fps_n, &_y4m->fps_d) != 2) { return -1;
} break;
} case'I': {
_y4m->interlace = p[1]; break;
} case'A': { if (sscanf(p + 1, "%d:%d", &_y4m->par_n, &_y4m->par_d) != 2) { return -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'; break;
} /*Ignore unknown tags.*/
}
} return 0;
}
// Copy a single tag into the buffer, along with a null character. // Returns 0 if any file IO errors occur. staticint copy_tag(char *buf, size_t buf_len, char *end_tag, FILE *file) {
size_t i;
assert(buf_len >= 1); // Skip leading space characters. do { if (!file_read(buf, 1, file)) { return 0;
}
} while (buf[0] == ' ');
// If we hit the newline, treat this as the "empty" tag. if (buf[0] == '\n') {
buf[0] = '\0';
*end_tag = '\n'; return 1;
}
// Copy over characters until a space is hit, or the buffer is exhausted. for (i = 1; i < buf_len; ++i) { if (!file_read(buf + i, 1, file)) { return 0;
} if (buf[i] == ' ' || buf[i] == '\n') { break;
}
} if (i == buf_len) {
fprintf(stderr, "Error: Y4M header tags must be less than %lu characters\n",
(unsignedlong)i); return 0;
}
*end_tag = buf[i];
buf[i] = '\0'; return 1;
}
/* Returns 1 if tags were parsed successfully, 0 otherwise. */ staticint parse_tags(y4m_input *y4m_ctx, FILE *file) { char tag[256]; char end; /* Character denoting the end of the tag, ' ' or '\n'. */ /* 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. */
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");
/* Find one tag at a time. */ do { if (!copy_tag(tag, sizeof(tag), &end, file)) { return 0;
} /* y4m_parse_tags returns 0 on success. */ if (y4m_parse_tags(y4m_ctx, tag)) { return 0;
}
} while (end != '\n');
/* 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): sinc(\pi*t)*sinc(\pi*t/3), |t|<3 (sinc(t)==sin(t)/t) 0, |t|>=3 The 4-tap Mitchell window (for up-sampling): 7|t|^3-12|t|^2+16/3, |t|<1 -(7/3)|x|^3+12|x|^2-20|x|+32/3, |t|<2 0, |t|>=2 The number of taps is intentionally kept small to reduce computational overhead and limit ringing.
The taps from these filters are scaled so that their sum is 1, and the result is scaled by 128 and rounded to integers to create a filter whose intermediate values fit inside 16 bits. Coefficients are rounded in such a way as to ensure their sum is still 128, which is usually equivalent to normal rounding.
Conversions which require both horizontal and vertical filtering could have these steps pipelined, for less memory consumption and better cache
performance, but we do them separately for simplicity.*/ #define OC_MINI(_a, _b) ((_a) > (_b) ? (_b) : (_a)) #define OC_MAXI(_a, _b) ((_a) < (_b) ? (_b) : (_a)) #define OC_CLAMPI(_a, _b, _c) (OC_MAXI(_a, OC_MINI(_b, _c)))
We use a resampling filter to shift the original site locations one quarter pixel (at the original chroma resolution) to the right. Then we use a second resampling filter to decimate the chroma planes by two
in the vertical direction.*/ staticvoid y4m_convert_422_420jpeg(y4m_input *_y4m, unsignedchar *_dst, unsignedchar *_aux) { unsignedchar *tmp; int c_w; int c_h; int c_sz; int dst_c_h; int dst_c_sz; int pli; /*Skip past the luma data.*/
_dst += _y4m->pic_w * _y4m->pic_h; /*Compute the size of each chroma plane.*/
c_w = (_y4m->pic_w + _y4m->src_c_dec_h - 1) / _y4m->src_c_dec_h;
c_h = _y4m->pic_h;
dst_c_h = (_y4m->pic_h + _y4m->dst_c_dec_v - 1) / _y4m->dst_c_dec_v;
c_sz = c_w * c_h;
dst_c_sz = c_w * dst_c_h;
tmp = _aux + 2 * c_sz; for (pli = 1; pli < 3; pli++) { /*In reality, the horizontal and vertical steps could be pipelined, for less memory consumption and better cache performance, but we do them
separately for simplicity.*/ /*First do horizontal filtering (convert to 422jpeg)*/
y4m_42xmpeg2_42xjpeg_helper(tmp, _aux, c_w, c_h); /*Now do the vertical filtering.*/
y4m_422jpeg_420jpeg_helper(_dst, tmp, c_w, c_h);
_aux += c_sz;
_dst += dst_c_sz;
}
}
int y4m_input_fetch_frame(y4m_input *_y4m, FILE *_fin, vpx_image_t *_img) { char frame[6]; int pic_sz; int c_w; int c_h; int c_sz; int bytes_per_sample = _y4m->bit_depth > 8 ? 2 : 1; /*Read and skip the frame header.*/ if (!file_read(frame, 6, _fin)) return 0; if (memcmp(frame, "FRAME", 5)) {
fprintf(stderr, "Loss of framing in Y4M input data\n"); return -1;
} if (frame[5] != '\n') { char c; int j; for (j = 0; j < 79 && file_read(&c, 1, _fin) && c != '\n'; j++) {
} if (j == 79) {
fprintf(stderr, "Error parsing Y4M frame header\n"); return -1;
}
} /*Read the frame data that needs no conversion.*/ if (!file_read(_y4m->dst_buf, _y4m->dst_buf_read_sz, _fin)) {
fprintf(stderr, "Error reading Y4M frame data.\n"); return -1;
} /*Read the frame data that does need conversion.*/ if (!file_read(_y4m->aux_buf, _y4m->aux_buf_read_sz, _fin)) {
fprintf(stderr, "Error reading Y4M frame data.\n"); return -1;
} /*Now convert the just read frame.*/
(*_y4m->convert)(_y4m, _y4m->dst_buf, _y4m->aux_buf); /*Fill in the frame buffer pointers. We don't use vpx_img_wrap() because it forces padding for odd picture
sizes, which would require a separate fread call for every row.*/
memset(_img, 0, sizeof(*_img)); /*Y4M has the planes in Y'CbCr order, which libvpx calls Y, U, and V.*/
_img->fmt = _y4m->vpx_fmt;
_img->w = _img->d_w = _y4m->pic_w;
_img->h = _img->d_h = _y4m->pic_h;
_img->bit_depth = _y4m->bit_depth;
_img->x_chroma_shift = _y4m->dst_c_dec_h >> 1;
_img->y_chroma_shift = _y4m->dst_c_dec_v >> 1;
_img->bps = _y4m->bps;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.