UltraGrid
UltraGrid Low-Latency High-Resolution Transmission System
Loading...
Searching...
No Matches
y4m.c
Go to the documentation of this file.
1
7/*
8 * Copyright (c) 2022-2024, CESNET z.s.p.o.
9 *
10 * All rights reserved.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions are met:
14 *
15 * * Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 *
18 * * Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
26 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 * POSSIBILITY OF SUCH DAMAGE.
33 */
34
35#include <errno.h>
36#include <stdio.h>
37#include <stdlib.h>
38#include <string.h>
39
40#include "y4m.h"
41
42static bool y4m_process_chroma_type(char *c, struct y4m_metadata *info) {
43 info->bitdepth = 8;
44 if (strcmp(c, "444alpha") == 0) {
45 info->subsampling = Y4M_SUBS_YUVA;
46 return true;
47 }
48 if (strncmp(c, "mono", 4) == 0) {
49 info->subsampling = Y4M_SUBS_MONO;
50 sscanf(c, "mono%d", &info->bitdepth);
51 return true;
52 }
53 int subsampling = 0;
54 if (sscanf(c, "%dp%d", &subsampling, &info->bitdepth) == 0) {
55 fprintf(stderr, "Y4M: unable to parse chroma type\n");
56 return false;
57 }
58 info->subsampling = subsampling;
59 return true;
60}
61
62static size_t y4m_get_data_len(const struct y4m_metadata *info) {
63 size_t ret = 0;
64 switch (info->subsampling) {
65 case Y4M_SUBS_MONO: ret = (size_t) info->width * info->height; break;
66 case Y4M_SUBS_420: ret = (size_t) info->width * info->height + (size_t) 2 * ((info->width + 1) / 2) * ((info->height + 1) / 2); break;
67 case Y4M_SUBS_422: ret = (size_t) info->width * info->height + (size_t) 2 * ((info->width + 1) / 2) * info->height; break;
68 case Y4M_SUBS_444: ret = (size_t) info->width * info->height * 3; break;
69 case Y4M_SUBS_YUVA: ret = (size_t) info->width * info->height * 4; break;
70 default:
71 fprintf(stderr, "Unsupported subsampling '%d'\n", info->subsampling);
72 return 0;
73 }
74 return ret * (info->bitdepth > 8 ? 2 : 1);
75}
76
77size_t y4m_read(const char *filename, struct y4m_metadata *info, unsigned char **data, void *(*allocator)(size_t)) {
78 FILE *file = fopen(filename, "rb");
79 if (!file) {
80 fprintf(stderr, "Failed to open %s: %s\n", filename, strerror(errno));
81 return 0;
82 }
83 char item[129];
84 if (fscanf(file, "%128s", item) != 1 || strcmp(item, "YUV4MPEG2") != 0) {
85 fprintf(stderr, "File '%s' doesn't seem to be valid Y4M.\n", filename);
86 fclose(file);
87 return 0;
88 }
89 memset(info, 0, sizeof *info);
90 info->width = info->height = info->bitdepth = info->subsampling = 0;
91 while (fscanf(file, " %128s", item) == 1 && strcmp(item, "FRAME") != 0) {
92 switch (item[0]) {
93 case 'W': info->width = atoi(item + 1); break;
94 case 'H': info->height = atoi(item + 1); break;
95 case 'C':
96 if (!y4m_process_chroma_type(item + 1, info)) {
97 fclose(file);
98 return 0;
99 }
100 break;
101 case 'X':
102 if (strcmp(item, "XCOLORRANGE=LIMITED") == 0) {
103 info->limited = true;
104 }
105 // F, I, A currently ignored
106 }
107 }
108 if (getc(file) != '\n') { // after FRAME
109 fclose(file);
110 return 0;
111 }
112 size_t datalen = y4m_get_data_len(info);
113 if (data == NULL || allocator == NULL) {
114 fclose(file);
115 return datalen;
116 }
117 *data = (unsigned char *) allocator(datalen);
118 if (!*data) {
119 fprintf(stderr, "Unspecified depth header field!\n");
120 fclose(file);
121 return 0;
122 }
123 errno = 0;
124 size_t bytes_read = fread((char *) *data, 1, datalen, file);
125 if (bytes_read != datalen) {
126 fprintf(stderr, "Unable to load %zd data bytes from Y4M file, read %zd bytes: %s\n",
127 datalen, bytes_read, feof(file) ? "EOF" : strerror(errno));
128 fclose(file);
129 return 0;
130 }
131 fclose(file);
132 return datalen;
133}
134
135bool y4m_write(const char *filename, const struct y4m_metadata *info, const unsigned char *data) {
136 errno = 0;
137 FILE *file = fopen(filename, "wb");
138 if (!file) {
139 fprintf(stderr, "Failed to open %s for writing: %s\n", filename, strerror(errno));
140 return false;
141 }
142 char chroma_type[42];
143 if (info->subsampling == Y4M_SUBS_MONO) {
144 snprintf(chroma_type, sizeof chroma_type, "mono");
145 } else if (info->subsampling == Y4M_SUBS_YUVA) {
146 if (info->bitdepth != 8) {
147 fprintf(stderr, "Only 8-bit 444alpha is supported for Y4M!\n");
148 fclose(file);
149 return false;
150 }
151 snprintf(chroma_type, sizeof chroma_type, "444alpha");
152 } else {
153 snprintf(chroma_type, sizeof chroma_type, "%d", info->subsampling);
154 }
155 size_t len = y4m_get_data_len(info);
156 if (len == 0) {
157 fclose(file);
158 return false;
159 }
160 if (info->bitdepth > 8) {
161 snprintf(chroma_type + strlen(chroma_type), sizeof chroma_type - strlen(chroma_type), "%s%d",
162 info->subsampling != Y4M_SUBS_MONO ? "p" : "", info->bitdepth); // 'p' in 420p10 but not mono10
163 }
164
165 fprintf(file, "YUV4MPEG2 W%d H%d F25:1 Ip A0:0 C%s XCOLORRANGE=%s\nFRAME\n",
166 info->width, info->height, chroma_type, info->limited ? "LIMITED" : "FULL");
167 errno = 0;
168 size_t bytes_written = fwrite((const char *) data, 1, len, file);
169 if (bytes_written != len) {
170 fprintf(stderr, "Unable to write Y4M data - length %zd, written %zd: %s\n",
171 len, bytes_written, strerror(errno));
172 }
173 fclose(file);
174 return bytes_written == len;
175}
176
int void size_t * len
Definition hd-rum.c:27
subsampling
Definition types.h:132
static bool y4m_process_chroma_type(char *c, struct y4m_metadata *info)
Definition y4m.c:42
size_t y4m_read(const char *filename, struct y4m_metadata *info, unsigned char **data, void *(*allocator)(size_t))
Definition y4m.c:77
static size_t y4m_get_data_len(const struct y4m_metadata *info)
Definition y4m.c:62
bool y4m_write(const char *filename, const struct y4m_metadata *info, const unsigned char *data)
Definition y4m.c:135
@ Y4M_SUBS_MONO
Definition y4m.h:50
@ Y4M_SUBS_444
Definition y4m.h:53
@ Y4M_SUBS_422
Definition y4m.h:52
@ Y4M_SUBS_420
Definition y4m.h:51
@ Y4M_SUBS_YUVA
Definition y4m.h:54