Cineform: 12-bit decoding

This commit is contained in:
Martin Piatka
2019-02-25 14:02:28 +01:00
parent 3aa85b5869
commit ada2d3874e
3 changed files with 352 additions and 8 deletions

View File

@@ -1543,6 +1543,231 @@ void vc_copylineRGBtoR12L(unsigned char *dst, const unsigned char *src, int dst_
}
}
/**
* @brief Converts R12L to RG48.
* Converts 12-bit packed RGB in full range (compatible with
* SMPTE 268M DPX version 1, Annex C, Method C4 packing) to 16-bit RGB
* @copydetails vc_copylinev210
*/
void vc_copylineR12LtoRG48(unsigned char *dst, const unsigned char *src, int dst_len)
{
while(dst_len >= 48){
//0
//R
*dst++ = src[BYTE_SWAP(0)] << 4;
*dst++ = (src[BYTE_SWAP(1)] << 4) | (src[BYTE_SWAP(0)] >> 4);
//G
*dst++ = src[BYTE_SWAP(1)] & 0xF0;
*dst++ = src[BYTE_SWAP(2)];
//B
*dst++ = src[BYTE_SWAP(3)] << 4;
*dst++ = (src[4 + BYTE_SWAP(0)] << 4) | (src[BYTE_SWAP(3)] >> 4);
//1
*dst++ = src[4 + BYTE_SWAP(0)] & 0xF0;
*dst++ = src[4 + BYTE_SWAP(1)];
*dst++ = src[4 + BYTE_SWAP(2)] << 4;
*dst++ = (src[4 + BYTE_SWAP(3)] << 4) | (src[4 + BYTE_SWAP(2)] >> 4);
*dst++ = src[4 + BYTE_SWAP(3)] & 0xF0;
*dst++ = src[8 + BYTE_SWAP(0)];
//2
*dst++ = src[8 + BYTE_SWAP(1)] << 4;
*dst++ = (src[8 + BYTE_SWAP(2)] << 4) | (src[8 + BYTE_SWAP(1)] >> 4);
*dst++ = src[8 + BYTE_SWAP(2)] & 0xF0;
*dst++ = src[8 + BYTE_SWAP(3)];
*dst++ = src[12 + BYTE_SWAP(0)] << 4;
*dst++ = (src[12 + BYTE_SWAP(1)] << 4) | (src[12 + BYTE_SWAP(0)] >> 4);
//3
*dst++ = src[12 + BYTE_SWAP(1)] & 0xF0;
*dst++ = src[12 + BYTE_SWAP(2)];
*dst++ = src[12 + BYTE_SWAP(3)] << 4;
*dst++ = (src[16 + BYTE_SWAP(0)] << 4) | (src[12 + BYTE_SWAP(3)] >> 4);
*dst++ = src[16 + BYTE_SWAP(0)] & 0xF0;
*dst++ = src[16 + BYTE_SWAP(1)];
//4
*dst++ = src[16 + BYTE_SWAP(2)] << 4;
*dst++ = (src[16 + BYTE_SWAP(3)] << 4) | (src[16 + BYTE_SWAP(2)] >> 4);
*dst++ = src[16 + BYTE_SWAP(3)] & 0xF0;
*dst++ = src[20 + BYTE_SWAP(0)];
*dst++ = src[20 + BYTE_SWAP(1)] << 4;
*dst++ = (src[20 + BYTE_SWAP(2)] << 4) | (src[20 + BYTE_SWAP(1)] >> 4);
//5
*dst++ = src[20 + BYTE_SWAP(2)] & 0xF0;
*dst++ = src[20 + BYTE_SWAP(3)];
*dst++ = src[24 + BYTE_SWAP(0)] << 4;
*dst++ = (src[24 + BYTE_SWAP(1)] << 4) | (src[24 + BYTE_SWAP(0)] >> 4);
*dst++ = src[24 + BYTE_SWAP(1)] & 0xF0;
*dst++ = src[24 + BYTE_SWAP(2)];
//6
*dst++ = src[24 + BYTE_SWAP(3)] << 4;
*dst++ = (src[28 + BYTE_SWAP(0)] << 4) | (src[24 + BYTE_SWAP(3)] >> 4);
*dst++ = src[28 + BYTE_SWAP(0)] & 0xF0;
*dst++ = src[28 + BYTE_SWAP(1)];
*dst++ = src[28 + BYTE_SWAP(2)] << 4;
*dst++ = (src[28 + BYTE_SWAP(3)] << 4) | (src[28 + BYTE_SWAP(2)] >> 4);
//7
*dst++ = src[28 + BYTE_SWAP(3)] & 0xF0;
*dst++ = src[32 + BYTE_SWAP(0)];
*dst++ = src[32 + BYTE_SWAP(1)] << 4;
*dst++ = (src[32 + BYTE_SWAP(2)] << 4) | (src[32 + BYTE_SWAP(1)] >> 4);
*dst++ = src[32 + BYTE_SWAP(2)] & 0xF0;
*dst++ = src[32 + BYTE_SWAP(3)];
dst_len -= 48;
src += 36;
}
}
/**
* @brief Converts RG48 to R12L.
* Converts 16-bit RGB to 12-bit packed RGB in full range (compatible with
* SMPTE 268M DPX version 1, Annex C, Method C4 packing)
* @copydetails vc_copylinev210
*/
void vc_copylineRG48toR12L(unsigned char *dst, const unsigned char *src, int dst_len)
{
while(dst_len >= 36){
//0
dst[BYTE_SWAP(0)] = src[0] >> 4;
dst[BYTE_SWAP(0)] |= src[1] << 4;
dst[BYTE_SWAP(1)] = src[1] >> 4;
src += 2;
dst[BYTE_SWAP(1)] |= src[0] & 0xF0;
dst[BYTE_SWAP(2)] = src[1];
src += 2;
dst[BYTE_SWAP(3)] = src[0] >> 4;
dst[BYTE_SWAP(3)] |= src[1] << 4;
dst[4 + BYTE_SWAP(0)] = src[1] >> 4;
src += 2;
//1
dst[4 + BYTE_SWAP(0)] |= src[0] & 0xF0;
dst[4 + BYTE_SWAP(1)] = src[1];
src += 2;
dst[4 + BYTE_SWAP(2)] = src[0] >> 4;
dst[4 + BYTE_SWAP(2)] |= src[1] << 4;
dst[4 + BYTE_SWAP(3)] = src[1] >> 4;
src += 2;
dst[4 + BYTE_SWAP(3)] |= src[0] & 0xF0;
dst[8 + BYTE_SWAP(0)] = src[1];
src += 2;
//2
dst[8 + BYTE_SWAP(1)] = src[0] >> 4;
dst[8 + BYTE_SWAP(1)] |= src[1] << 4;
dst[8 + BYTE_SWAP(2)] = src[1] >> 4;
src += 2;
dst[8 + BYTE_SWAP(2)] |= src[0] & 0xF0;
dst[8 + BYTE_SWAP(3)] = src[1];
src += 2;
dst[12 + BYTE_SWAP(0)] = src[0] >> 4;
dst[12 + BYTE_SWAP(0)] |= src[1] << 4;
dst[12 + BYTE_SWAP(1)] = src[1] >> 4;
src += 2;
//3
dst[12 + BYTE_SWAP(1)] |= src[0] & 0xF0;
dst[12 + BYTE_SWAP(2)] = src[1];
src += 2;
dst[12 + BYTE_SWAP(3)] = src[0] >> 4;
dst[12 + BYTE_SWAP(3)] |= src[1] << 4;
dst[16 + BYTE_SWAP(0)] = src[1] >> 4;
src += 2;
dst[16 + BYTE_SWAP(0)] |= src[0] & 0xF0;
dst[16 + BYTE_SWAP(1)] = src[1];
src += 2;
//4
dst[16 + BYTE_SWAP(2)] = src[0] >> 4;
dst[16 + BYTE_SWAP(2)] |= src[1] << 4;
dst[16 + BYTE_SWAP(3)] = src[1] >> 4;
src += 2;
dst[16 + BYTE_SWAP(3)] |= src[0] & 0xF0;
dst[20 + BYTE_SWAP(0)] = src[1];
src += 2;
dst[20 + BYTE_SWAP(1)] = src[0] >> 4;
dst[20 + BYTE_SWAP(1)] |= src[1] << 4;
dst[20 + BYTE_SWAP(2)] = src[1] >> 4;
src += 2;
//5
dst[20 + BYTE_SWAP(2)] |= src[0] & 0xF0;
dst[20 + BYTE_SWAP(3)] = src[1];
src += 2;
dst[24 + BYTE_SWAP(0)] = src[0] >> 4;
dst[24 + BYTE_SWAP(0)] |= src[1] << 4;
dst[24 + BYTE_SWAP(1)] = src[1] >> 4;
src += 2;
dst[24 + BYTE_SWAP(1)] |= src[0] & 0xF0;
dst[24 + BYTE_SWAP(2)] = src[1];
src += 2;
//6
dst[24 + BYTE_SWAP(3)] = src[0] >> 4;
dst[24 + BYTE_SWAP(3)] |= src[1] << 4;
dst[28 + BYTE_SWAP(0)] = src[1] >> 4;
src += 2;
dst[28 + BYTE_SWAP(0)] |= src[0] & 0xF0;
dst[28 + BYTE_SWAP(1)] = src[1];
src += 2;
dst[28 + BYTE_SWAP(2)] = src[0] >> 4;
dst[28 + BYTE_SWAP(2)] |= src[1] << 4;
dst[28 + BYTE_SWAP(3)] = src[1] >> 4;
src += 2;
//7
dst[28 + BYTE_SWAP(3)] |= src[0] & 0xF0;
dst[32 + BYTE_SWAP(0)] = src[1];
src += 2;
dst[32 + BYTE_SWAP(1)] = src[0] >> 4;
dst[32 + BYTE_SWAP(1)] |= src[1] << 4;
dst[32 + BYTE_SWAP(2)] = src[1] >> 4;
src += 2;
dst[32 + BYTE_SWAP(2)] |= src[0] & 0xF0;
dst[32 + BYTE_SWAP(3)] = src[1];
src += 2;
dst += 36;
dst_len -= 36;
}
}
/**
* @brief Converts RGB to UYVY.
* Uses full scale Rec. 601 YUV (aka JPEG)

View File

@@ -115,6 +115,7 @@ void vc_copylineRGBtoGrayscale_SSE(unsigned char *dst, const unsigned char *src,
void vc_copylineRGBtoR12L(unsigned char *dst, const unsigned char *src, int len,
int rshift, int gshift, int bshift);
void vc_copylineR12LtoRG48(unsigned char *dst, const unsigned char *src, int len);
void vc_copylineRG48toR12L(unsigned char *dst, const unsigned char *src, int len);
void vc_copylineUYVYtoRGB(unsigned char *dst, const unsigned char *src, int len);
void vc_copylineUYVYtoRGB_SSE(unsigned char *dst, const unsigned char *src, int len);
void vc_copylineUYVYtoGrayscale(unsigned char *dst, const unsigned char *src, int len);

View File

@@ -1,3 +1,41 @@
/**
* @file video_decompress/cineform.cpp
* @author Martin Piatka <piatka@cesnet.cz>
*/
/*
* Copyright (c) 2019 CESNET, z. s. p. o.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, is permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of CESNET nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#include "config_unix.h"
@@ -15,6 +53,9 @@
#include "CFHDTypes.h"
#include "CFHDDecoder.h"
#include <mutex>
#include <vector>
struct state_cineform_decompress {
int width, height;
int pitch;
@@ -22,6 +63,11 @@ struct state_cineform_decompress {
int max_compressed_len;
codec_t in_codec;
codec_t out_codec;
CFHD_PixelFormat decode_codec;
void (*convert)(unsigned char *dst_buffer,
unsigned char *src_buffer,
int width, int height, int pitch);
std::vector<unsigned char> conv_buf;
unsigned last_frame_seq:22; // This gives last sucessfully decoded frame seq number. It is the buffer number from the packet format header, uses 22 bits.
bool last_frame_seq_initialized;
@@ -39,6 +85,7 @@ static void * cineform_decompress_init(void)
s = new state_cineform_decompress();
s->width = s->height = s->pitch = 0;
s->convert = nullptr;
s->prepared_to_decode = false;
CFHD_Error status;
@@ -59,6 +106,31 @@ static void cineform_decompress_done(void *state)
delete s;
}
static void rg48_to_r12l(unsigned char *dst_buffer,
unsigned char *src_buffer,
int width, int height, int pitch)
{
int src_pitch = vc_get_linesize(width, RG48);
int dst_pitch = vc_get_linesize(width, R12L);
for(unsigned i = 0; i < height; i++){
vc_copylineRG48toR12L(dst_buffer, src_buffer, dst_pitch);
src_buffer += src_pitch;
dst_buffer += dst_pitch;
}
}
static const struct {
codec_t ug_codec;
CFHD_PixelFormat cfhd_pixfmt;
void (*convert)(unsigned char *dst_buffer,
unsigned char *src_buffer,
int width, int height, int pitch);
} decode_codecs[] = {
{R12L, CFHD_PIXEL_FORMAT_RG48, rg48_to_r12l},
{UYVY, CFHD_PIXEL_FORMAT_2VUY, nullptr},
};
static bool configure_with(struct state_cineform_decompress *s,
struct video_desc desc)
{
@@ -66,7 +138,19 @@ static bool configure_with(struct state_cineform_decompress *s,
s->prepared_to_decode = false;
s->saved_desc = desc;
return true;
for(const auto& i : decode_codecs){
if(i.ug_codec == s->out_codec){
s->decode_codec = i.cfhd_pixfmt;
s->convert = i.convert;
CFHD_GetImagePitch(desc.width, i.cfhd_pixfmt, &s->pitch);
if(i.ug_codec == R12L){
log_msg(LOG_LEVEL_NOTICE, "[cineform] Using decoding to 12-bit RGB.\n");
}
return true;
}
}
return false;
}
static int cineform_decompress_reconfigure(void *state, struct video_desc desc,
@@ -75,10 +159,10 @@ static int cineform_decompress_reconfigure(void *state, struct video_desc desc,
struct state_cineform_decompress *s =
(struct state_cineform_decompress *) state;
s->pitch = pitch;
assert(out_codec == UYVY ||
out_codec == RGB ||
out_codec == v210);
out_codec == v210 ||
out_codec == R12L);
s->pitch = pitch;
s->rshift = rshift;
@@ -108,7 +192,7 @@ static bool prepare(struct state_cineform_decompress *s,
status = CFHD_PrepareToDecode(s->decoderRef,
s->saved_desc.width,
s->saved_desc.height,
CFHD_PIXEL_FORMAT_2VUY,
s->decode_codec,
CFHD_DECODED_RESOLUTION_FULL,
CFHD_DECODING_FLAGS_NONE,
src,
@@ -122,7 +206,12 @@ static bool prepare(struct state_cineform_decompress *s,
int actualPitch;
CFHD_GetImagePitch(actualWidth, actualFormat, &actualPitch);
assert(actualPitch == s->pitch);
assert(actualFormat == CFHD_PIXEL_FORMAT_2VUY);
assert(actualFormat == s->decode_codec);
if(s->convert){
s->conv_buf.resize(s->height * s->pitch);
} else {
s->conv_buf.clear();
}
if(status != CFHD_ERROR_OKAY){
log_msg(LOG_LEVEL_ERROR, "[cineform] Failed to prepare for decoding\n");
return false;
@@ -144,13 +233,18 @@ static decompress_status cineform_decompress(void *state, unsigned char *dst, un
return res;
}
unsigned char *decode_dst = s->convert ? s->conv_buf.data() : dst;
status = CFHD_DecodeSample(s->decoderRef,
src,
src_len,
dst,
decode_dst,
s->pitch);
if(status == CFHD_ERROR_OKAY){
if(s->convert){
s->convert(dst, decode_dst, s->width, s->height, s->pitch);
}
res = DECODER_GOT_FRAME;
} else {
log_msg(LOG_LEVEL_ERROR, "[cineform] Failed to decode %i\n", status);
@@ -185,12 +279,36 @@ static int cineform_decompress_get_property(void *state, int property, void *val
return ret;
}
ADD_TO_PARAM(lavd_use_10bit, "cfhd-use-12bit",
"* cfhd-use-12bit\n"
" Indicates that we are using decoding to R12L.\n"
" With this flag, R12L (12-bit RGB)\n"
" will be announced as a supported codec.\n");
static const struct decode_from_to *cineform_decompress_get_decoders() {
static const struct decode_from_to dec_static[] = {
const struct decode_from_to dec_static[] = {
{ CFHD, UYVY, 500 },
};
return dec_static;
static struct decode_from_to ret[sizeof dec_static / sizeof dec_static[0]
+ 1 /* terminating zero */
+ 10 /* place for additional decoders, see below */];
static std::mutex mutex;
std::lock_guard<std::mutex> lock(mutex);
if (ret[0].from == VIDEO_CODEC_NONE) { // not yet initialized
memcpy(ret, dec_static, sizeof dec_static);
if (get_commandline_param("cfhd-use-12bit")) {
log_msg(LOG_LEVEL_NOTICE, "[cineform] param 12-bit RGB.\n");
//Report only 12-bit formats
ret[0] = (struct decode_from_to) {CFHD, R12L, 100};
ret[1] = { };
}
}
return ret;
}
static const struct video_decompress_info cineform_info = {