UltraGrid
UltraGrid Low-Latency High-Resolution Transmission System
Loading...
Searching...
No Matches
cineform.cpp
Go to the documentation of this file.
1
5/*
6 * Copyright (c) 2019-2023 CESNET, z. s. p. o.
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, is permitted provided that the following conditions
11 * are met:
12 *
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 *
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 *
20 * 3. Neither the name of CESNET nor the names of its contributors may be
21 * used to endorse or promote products derived from this software without
22 * specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS
25 * "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING,
26 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
27 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
28 * EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
29 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
30 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
31 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
34 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
35 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 */
37
38
39#ifdef HAVE_CONFIG_H
40#include "config.h"
41#include "config_unix.h"
42#include "config_win32.h"
43#endif // HAVE_CONFIG_H
44
45#include "debug.h"
46#include "host.h"
47#include "lib_common.h"
48#include "tv.h"
49#include "video.h"
50#include "video_decompress.h"
51#include "utils/macros.h" // to_fourcc
52
53#include "CFHDTypes.h"
54#include "CFHDDecoder.h"
55
56#include <vector>
57
60 int pitch;
65 CFHD_PixelFormat decode_codec;
67 void (*convert)(unsigned char *dst_buffer,
68 unsigned char *src_buffer,
69 int width, int height, int pitch);
70 std::vector<unsigned char> conv_buf;
71
73
74 CFHD_DecoderRef decoderRef;
75 CFHD_MetadataRef metadataRef;
76
78};
79
80static void * cineform_decompress_init(void)
81{
83
85
86 s->width = s->height = s->pitch = s->decode_linesize = 0;
87 s->convert = nullptr;
88 s->prepared_to_decode = false;
89
90 CFHD_Error status;
91 status = CFHD_OpenDecoder(&s->decoderRef, nullptr);
92 if(status != CFHD_ERROR_OKAY){
93 log_msg(LOG_LEVEL_ERROR, "[cineform] Failed to open decoder\n");
94 }
95 status = CFHD_OpenMetadata(&s->metadataRef);
96 if(status != CFHD_ERROR_OKAY){
97 log_msg(LOG_LEVEL_ERROR, "[cineform] Failed to open metadata\n");
98 CFHD_CloseDecoder(s->decoderRef);
99 }
100
101 return s;
102}
103
105{
106 struct state_cineform_decompress *s =
108
109 CFHD_CloseDecoder(s->decoderRef);
110 CFHD_CloseMetadata(s->metadataRef);
111 delete s;
112}
113
114static void rg48_to_r12l(unsigned char *dst_buffer,
115 unsigned char *src_buffer,
116 int width, int height, int pitch)
117{
118 int src_pitch = vc_get_linesize(width, RG48);
119 int dst_len = vc_get_linesize(width, R12L);
121
122 for(int i = 0; i < height; i++){
123 vc_copylineRG48toR12L(dst_buffer, src_buffer, dst_len, 0, 0, 0);
124 src_buffer += src_pitch;
125 dst_buffer += pitch;
126 }
127}
128
129static void abgr_to_rgba(unsigned char *dst_buffer,
130 unsigned char *src_buffer,
131 int width, int height, int pitch)
132{
133 int linesize = vc_get_linesize(width, RGBA);
134
135 for(int i = 0; i < height; i++){
136 vc_copylineRGBA(dst_buffer, src_buffer, linesize, 16, 8, 0);
137 src_buffer += linesize;
138 dst_buffer += pitch;
139 }
140}
141
142static void bgr_to_rgb_invert(unsigned char *dst_buffer,
143 unsigned char *src_buffer,
144 int width, int height, int pitch)
145{
146 int linesize = vc_get_linesize(width, RGB);
147 src_buffer += linesize * (height - 1);
149
150 for(int i = 0; i < height; i++){
151 vc_copylineBGRtoRGB(dst_buffer, src_buffer, linesize, 0, 0, 0);
152 src_buffer -= linesize;
153 dst_buffer += pitch;
154 }
155}
156
157static const struct {
159 CFHD_PixelFormat cfhd_pixfmt;
160 void (*convert)(unsigned char *dst_buffer,
161 unsigned char *src_buffer,
162 int width, int height, int pitch);
163} decode_codecs[] = {
164 {R12L, CFHD_PIXEL_FORMAT_RG48, rg48_to_r12l},
165 {RG48, CFHD_PIXEL_FORMAT_RG48, nullptr},
166 {UYVY, CFHD_PIXEL_FORMAT_2VUY, nullptr},
167 {R10k, CFHD_PIXEL_FORMAT_DPX0, nullptr},
168 {v210, CFHD_PIXEL_FORMAT_V210, nullptr},
169 {RGB, CFHD_PIXEL_FORMAT_RG24, bgr_to_rgb_invert},
170 {RGBA, CFHD_PIXEL_FORMAT_BGRa, abgr_to_rgba},
172
174 struct video_desc desc)
175{
176 s->prepared_to_decode = false;
177 s->saved_desc = desc;
178
179 if(s->out_codec == VIDEO_CODEC_NONE){
180 log_msg(LOG_LEVEL_DEBUG, "[cineform] Will probe for internal format.\n");
181 return true;
182 }
183
184 for(const auto& i : decode_codecs){
185 if(i.ug_codec == s->out_codec){
186 s->decode_codec = i.cfhd_pixfmt;
187 s->convert = i.convert;
188 CFHD_GetImagePitch(desc.width, i.cfhd_pixfmt, &s->decode_linesize);
189 if(i.ug_codec == R12L){
190 log_msg(LOG_LEVEL_NOTICE, "[cineform] Decoding to 12-bit RGB.\n");
191 }
192 return true;
193 }
194 }
195
196 return false;
197}
198
200 int rshift, int gshift, int bshift, int pitch, codec_t out_codec)
201{
202 struct state_cineform_decompress *s =
204
205 s->pitch = pitch;
206 s->rshift = rshift;
207 s->gshift = gshift;
208 s->bshift = bshift;
210 s->out_codec = out_codec;
211 s->width = desc.width;
212 s->height = desc.height;
213
214 return configure_with(s, desc);
215}
216
217static bool prepare(struct state_cineform_decompress *s,
218 unsigned char *src,
219 unsigned int src_len)
220{
221 if(s->prepared_to_decode){
222 return true;
223 }
224
225 CFHD_Error status;
226
227 int actualWidth;
228 int actualHeight;
229 CFHD_PixelFormat actualFormat;
230 status = CFHD_PrepareToDecode(s->decoderRef,
231 s->saved_desc.width,
233 s->decode_codec,
234 CFHD_DECODED_RESOLUTION_FULL,
235 CFHD_DECODING_FLAGS_NONE,
236 src,
237 src_len,
238 &actualWidth,
239 &actualHeight,
240 &actualFormat
241 );
242 assert(actualWidth == s->width);
243 assert(actualHeight == s->height);
244 assert(actualFormat == s->decode_codec);
245 if(s->convert){
246 int actualPitch;
247 CFHD_GetImagePitch(actualWidth, actualFormat, &actualPitch);
248 assert(actualPitch == s->decode_linesize);
249 s->conv_buf.resize(s->height * s->decode_linesize);
250 } else {
251 s->conv_buf.clear();
252 }
253 if(status != CFHD_ERROR_OKAY){
254 log_msg(LOG_LEVEL_ERROR, "[cineform] Failed to prepare for decoding\n");
255 return false;
256 }
257
258 s->prepared_to_decode = true;
259 return true;
260}
261
263 unsigned char *src,
264 unsigned src_len,
265 struct pixfmt_desc *internal_prop)
266{
267 CFHD_Error status;
268 CFHD_PixelFormat fmt_list[64];
269 int count = 0;
270
271 status = CFHD_GetOutputFormats(s->decoderRef,
272 src,
273 src_len,
274 fmt_list,
275 sizeof(fmt_list) / sizeof(fmt_list[0]),
276 &count);
277 log_msg(LOG_LEVEL_DEBUG, "[cineform] probing...\n");
278
279 if(status != CFHD_ERROR_OKAY){
280 log_msg(LOG_LEVEL_ERROR, "[cineform] probe failed\n");
281 return DECODER_NO_FRAME;
282 }
283
284 for(int i = 0; i < count; i++){
285 for(const auto &codec : decode_codecs){
286 if(codec.cfhd_pixfmt == fmt_list[i]){
287 *internal_prop = get_pixfmt_desc(codec.ug_codec);
288 return DECODER_GOT_CODEC;
289 }
290 }
291 }
292
293 //Unknown internal format. This should never happen since cineform can
294 //decode any internal codec to CFHD_PIXEL_FORMAT_YUY2.
295 //Here we just select UYVY and hope for the best.
296 *internal_prop = get_pixfmt_desc(UYVY);
297 return DECODER_GOT_CODEC;
298}
299
300static void write_fcc(char *out, int pixelformat){
301 out[4] = '\0';
302
303 for(int i = 0; i < 4; i++){
304 out[i] = pixelformat & 0xff;
305 pixelformat >>= 8;
306 }
307}
308
310 unsigned char *src,
311 unsigned src_len,
312 struct pixfmt_desc *internal_prop)
313{
314 CFHD_Error status;
315
316 status = CFHD_InitSampleMetadata(s->metadataRef,
317 METADATATYPE_ORIGINAL,
318 src,
319 src_len);
320 if(status != CFHD_ERROR_OKAY){
321 log_msg(LOG_LEVEL_ERROR, "[cineform] InitSampleMetadata failed\n");
322 return DECODER_NO_FRAME;
323 }
324
325 CFHD_MetadataTag tag;
326 CFHD_MetadataType type;
327 void *data;
328 CFHD_MetadataSize size;
329 char fcc[5];
330 while((status = CFHD_ReadMetadata(s->metadataRef, &tag, &type, &data, &size)) == CFHD_ERROR_OKAY){
331 write_fcc(fcc, tag);
332 log_msg(LOG_LEVEL_DEBUG, "[cineform] Metadata found. tag = %s \n", fcc);
333 }
334
335 status = CFHD_FindMetadata(s->metadataRef,
336 to_fourcc('U', 'G', 'P', 'F'),
337 &type,
338 &data,
339 &size);
340 if(status != CFHD_ERROR_OKAY || type != METADATATYPE_UINT32){
341 log_msg(LOG_LEVEL_ERROR, "[cineform] UGPF metadata not found or wrong type, "
342 "falling back to cineform internal format detection.\n");
343 } else {
344 codec_t pf = *static_cast<codec_t *>(data);
345 *internal_prop = get_pixfmt_desc(pf);
346 log_msg(LOG_LEVEL_NOTICE, "[cineform] Codec determined from metadata: %s \n", get_codec_name(pf));
347 return DECODER_GOT_CODEC;
348 }
349
350 return probe_internal_cineform(s, src, src_len, internal_prop);
351}
352
353static decompress_status cineform_decompress(void *state, unsigned char *dst, unsigned char *src,
354 unsigned int src_len, int frame_seq, struct video_frame_callbacks *callbacks,
355 struct pixfmt_desc *internal_prop)
356{
357 UNUSED(frame_seq);
358 UNUSED(callbacks);
361
362 CFHD_Error status;
363
364 if(s->out_codec == VIDEO_CODEC_NONE){
365 return probe_internal(s, src, src_len, internal_prop);
366 }
367
368 if(!prepare(s, src, src_len)){
369 return res;
370 }
371
372 unsigned char *decode_dst = s->convert ? s->conv_buf.data() : dst;
373 int pitch = s->convert ? s->decode_linesize : s->pitch;
374
375 status = CFHD_DecodeSample(s->decoderRef,
376 src,
377 src_len,
378 decode_dst,
379 pitch);
380
381 if(status == CFHD_ERROR_OKAY){
382 if(s->convert){
383 s->convert(dst, decode_dst, s->width, s->height, s->pitch);
384 }
385 res = DECODER_GOT_FRAME;
386 } else {
387 log_msg(LOG_LEVEL_ERROR, "[cineform] Failed to decode %i\n", status);
388 }
389
390 return res;
391}
392
393static int cineform_decompress_get_property(void *state, int property, void *val, size_t *len)
394{
395 struct state_cineform_decompress *s =
397 UNUSED(s);
398 int ret = FALSE;
399
400 switch(property) {
402 if(*len >= sizeof(int)) {
403#ifdef CINEFORM_ACCEPT_CORRUPTED
404 *(int *) val = TRUE;
405#else
406 *(int *) val = FALSE;
407#endif
408 *len = sizeof(int);
409 ret = TRUE;
410 }
411 break;
412 default:
413 ret = FALSE;
414 }
415
416 return ret;
417}
418
419static int cineform_decompress_get_priority(codec_t compression, struct pixfmt_desc internal, codec_t ugc) {
420 UNUSED(internal);
421 if (compression != CFHD) {
422 return -1;
423 }
424 switch (ugc) {
425 case VIDEO_CODEC_NONE: // probe
426 return 50;
427 case UYVY:
428 case RGBA:
429 case R10k:
430 case R12L:
431 case RG48:
432 case v210:
433 break;
434 default:
435 return -1;
436 }
437 return VDEC_PRIO_PREFERRED;
438}
439
448
#define UNUSED(x)
void ** state
int void * val
struct video_desc desc
int void size_t * len
int property
int vc_get_linesize(unsigned int width, codec_t codec)
const char * get_codec_name(codec_t codec)
#define TRUE
#define FALSE
void log_msg(int level, const char *format,...)
Definition debug.cpp:130
#define LOG_LEVEL_NOTICE
information that may be interesting
Definition debug.h:61
#define LOG_LEVEL_ERROR
general errors
Definition debug.h:59
decompress_status
#define DECOMPRESS_PROPERTY_ACCEPTS_CORRUPTED_FRAME
@ DECODER_GOT_CODEC
Internal pixel format was determined.
@ DECODER_NO_FRAME
@ DECODER_GOT_FRAME
@ VDEC_PRIO_PREFERRED
int count
Definition hd-rum.c:44
#define LOG_LEVEL_DEBUG
Definition kernels.cu:48
@ LIBRARY_CLASS_VIDEO_DECOMPRESS
Definition lib_common.h:81
#define REGISTER_MODULE(name, info, lclass, abi)
Registers module to global modules' registry.
Definition lib_common.h:144
#define to_fourcc(a, b, c, d)
Creates FourCC word.
Definition macros.h:114
decoder_t get_decoder_from_to(codec_t in, codec_t out)
static void vc_copylineRG48toR12L(unsigned char *__restrict dst, const unsigned char *__restrict src, int dst_len, int rshift, int gshift, int bshift)
Converts RG48 to R12L. Converts 16-bit RGB to 12-bit packed RGB in full range (compatible with SMPTE ...
static void vc_copylineBGRtoRGB(unsigned char *__restrict dst, const unsigned char *__restrict src, int dst_len, int rshift, int gshift, int bshift)
decoder_func_t vc_copylineRGBA
decoder_func_t * decoder_t
Definition pixfmt_conv.h:96
Option::OptType type
Definition settings.cpp:194
struct video_desc saved_desc
Definition cineform.cpp:77
std::vector< unsigned char > conv_buf
Definition cineform.cpp:70
CFHD_PixelFormat decode_codec
Definition cineform.cpp:65
CFHD_DecoderRef decoderRef
Definition cineform.cpp:74
void(* convert)(unsigned char *dst_buffer, unsigned char *src_buffer, int width, int height, int pitch)
Definition cineform.cpp:67
CFHD_MetadataRef metadataRef
Definition cineform.cpp:75
codec_t color_spec
Definition types.h:182
unsigned int width
width of every tile (!)
Definition types.h:179
unsigned int height
height of every tile (!)
Definition types.h:180
Struct containing callbacks of a video_frame.
Definition types.h:230
codec_t
Definition types.h:65
@ R10k
RGB 10-bit packed - RGBX, big-endian (2 bit padding)
Definition types.h:73
@ RGB
RGB 8-bit (packed into 24-bit word)
Definition types.h:80
@ UYVY
YCbCr 422 8-bit - Cb Y0 Cr Y1.
Definition types.h:71
@ VIDEO_CODEC_NONE
dummy color spec
Definition types.h:66
@ BGR
8-bit BGR
Definition types.h:88
@ RG48
16-bit RGB little-endian (RlRhGl...)
Definition types.h:95
@ CFHD
Cineform.
Definition types.h:94
@ R12L
RGB 12-bit packed, little-endian.
Definition types.h:74
@ RGBA
RGBA 8-bit, big-endian.
Definition types.h:70
@ v210
YCbCr 422 10-bit - xVY0U|xY2UY1|xUY3V|xY5VY4, little-endian (2 bit padding /'x'/),...
Definition types.h:75
This is an umbrella header for video functions.
struct pixfmt_desc get_pixfmt_desc(codec_t pixfmt)
static bool configure_with(struct state_video_compress_cineform *s, struct video_desc desc)
Definition cineform.cpp:243
const struct video_compress_info cineform_info
Definition cineform.cpp:533
codec_t ug_codec
Definition cineform.cpp:158
static int cineform_decompress_get_priority(codec_t compression, struct pixfmt_desc internal, codec_t ugc)
Definition cineform.cpp:419
static void abgr_to_rgba(unsigned char *dst_buffer, unsigned char *src_buffer, int width, int height, int pitch)
Definition cineform.cpp:129
static int cineform_decompress_reconfigure(void *state, struct video_desc desc, int rshift, int gshift, int bshift, int pitch, codec_t out_codec)
Definition cineform.cpp:199
static decompress_status probe_internal(struct state_cineform_decompress *s, unsigned char *src, unsigned src_len, struct pixfmt_desc *internal_prop)
Definition cineform.cpp:309
static void rg48_to_r12l(unsigned char *dst_buffer, unsigned char *src_buffer, int width, int height, int pitch)
Definition cineform.cpp:114
static decompress_status cineform_decompress(void *state, unsigned char *dst, unsigned char *src, unsigned int src_len, int frame_seq, struct video_frame_callbacks *callbacks, struct pixfmt_desc *internal_prop)
Definition cineform.cpp:353
static void write_fcc(char *out, int pixelformat)
Definition cineform.cpp:300
static decompress_status probe_internal_cineform(struct state_cineform_decompress *s, unsigned char *src, unsigned src_len, struct pixfmt_desc *internal_prop)
Definition cineform.cpp:262
static void * cineform_decompress_init(void)
Definition cineform.cpp:80
static const struct @81 decode_codecs[]
static void cineform_decompress_done(void *state)
Definition cineform.cpp:104
static int cineform_decompress_get_property(void *state, int property, void *val, size_t *len)
Definition cineform.cpp:393
static void bgr_to_rgb_invert(unsigned char *dst_buffer, unsigned char *src_buffer, int width, int height, int pitch)
Definition cineform.cpp:142
CFHD_PixelFormat cfhd_pixfmt
Definition cineform.cpp:159
static bool prepare(struct state_cineform_decompress *s, unsigned char *src, unsigned int src_len)
Definition cineform.cpp:217
API for video decompress drivers.
#define VIDEO_DECOMPRESS_ABI_VERSION