Refactor sdmp2sox a lot
Also adds fakeexpand mode and dedup support.
This commit is contained in:
parent
20fb1ccf70
commit
3526ae2c10
1 changed files with 207 additions and 305 deletions
512
sdmp2sox.cpp
512
sdmp2sox.cpp
|
@ -15,9 +15,15 @@
|
|||
#define FLAG_CS_MASK 48
|
||||
#define FLAG_8BIT 64
|
||||
#define FLAG_FAKENLARGE 128
|
||||
#define FLAG_DEDUP 256
|
||||
|
||||
|
||||
#define MAX_DEDUP 9
|
||||
|
||||
//Heh, this happens to be exact hardware capacity of 1.44MB 90mm floppy. :-)
|
||||
//This buffer needs to be big enough to store 512x480 16-bit YCbCr 4:4:4 (6 bytes per pixel) image.
|
||||
unsigned char yuv_buffer[1474560];
|
||||
unsigned char old_yuv_buffer[1474560];
|
||||
|
||||
//30 bit values.
|
||||
uint32_t ymatrix[0x80000];
|
||||
|
@ -35,179 +41,158 @@ uint32_t crmatrix[0x80000];
|
|||
Cr += crmatrix[c & 0x7FFFF];\
|
||||
} while(0)
|
||||
|
||||
#define STORE16(buffer,idx,shift,psep,v1,v2,v3)\
|
||||
buffer[(idx)] = (v1 >> ((shift) + 8));\
|
||||
buffer[(idx) + 1] = (v1 >> (shift));\
|
||||
buffer[(idx) + (psep)] = (v2 >> ((shift) + 8));\
|
||||
buffer[(idx) + 1 + (psep)] = (v2 >> (shift));\
|
||||
buffer[(idx) + 2 * (psep)] = (v3 >> ((shift) + 8));\
|
||||
buffer[(idx) + 1 + 2 * (psep)] = (v3 >> (shift));
|
||||
#define RGB2YUV_SHIFT 14
|
||||
|
||||
#define STORE8(buffer,idx,shift,psep,v1,v2,v3)\
|
||||
buffer[(idx)] = (v1 >> ((shift) + 8));\
|
||||
buffer[(idx) + (psep)] = (v2 >> ((shift) + 8));\
|
||||
buffer[(idx) + 2 * (psep)] = (v3 >> ((shift) + 8);\
|
||||
|
||||
template<unsigned shift>
|
||||
struct store16
|
||||
{
|
||||
static const size_t esize = 2;
|
||||
static void store(unsigned char* buffer, size_t idx, size_t psep, uint32_t v1, uint32_t v2,
|
||||
uint32_t v3)
|
||||
{
|
||||
*reinterpret_cast<uint16_t*>(buffer + idx) = (v1 >> shift);
|
||||
*reinterpret_cast<uint16_t*>(buffer + idx + psep) = (v2 >> shift);
|
||||
*reinterpret_cast<uint16_t*>(buffer + idx + 2 * psep) = (v3 >> shift);
|
||||
*reinterpret_cast<uint16_t*>(buffer + idx) = (v1 >> RGB2YUV_SHIFT);
|
||||
*reinterpret_cast<uint16_t*>(buffer + idx + psep) = (v2 >> RGB2YUV_SHIFT);
|
||||
*reinterpret_cast<uint16_t*>(buffer + idx + 2 * psep) = (v3 >> RGB2YUV_SHIFT);
|
||||
}
|
||||
};
|
||||
|
||||
template<unsigned shift>
|
||||
struct store8
|
||||
{
|
||||
static const size_t esize = 1;
|
||||
static void store(unsigned char* buffer, size_t idx, size_t psep, uint32_t v1, uint32_t v2,
|
||||
uint32_t v3)
|
||||
{
|
||||
buffer[idx] = (v1 >> (shift + 8));
|
||||
buffer[idx + psep] = (v2 >> (shift + 8));
|
||||
buffer[idx + 2 * psep] = (v3 >> (shift + 8));
|
||||
buffer[idx] = (v1 >> (RGB2YUV_SHIFT + 8));
|
||||
buffer[idx + psep] = (v2 >> (RGB2YUV_SHIFT + 8));
|
||||
buffer[idx + 2 * psep] = (v3 >> (RGB2YUV_SHIFT + 8));
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct store_11
|
||||
template<class store, size_t ioff1, size_t ioff2, size_t ioff3, size_t ooff1, size_t ooff2, size_t ooff3>
|
||||
struct loadstore
|
||||
{
|
||||
static const size_t esize = T::esize;
|
||||
static void store(unsigned char* buffer, size_t idx, size_t psep, uint32_t v1, uint32_t v2,
|
||||
uint32_t v3)
|
||||
{
|
||||
T::store(buffer, idx, psep, v1, v2, v3);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct store_12
|
||||
{
|
||||
static const size_t esize = 2 * T::esize;
|
||||
static void store(unsigned char* buffer, size_t idx, size_t psep, uint32_t v1, uint32_t v2,
|
||||
uint32_t v3)
|
||||
{
|
||||
T::store(buffer, idx, psep, v1, v2, v3);
|
||||
T::store(buffer, idx + T::esize, psep, v1, v2, v3);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T, size_t llen>
|
||||
struct store_21
|
||||
{
|
||||
static const size_t esize = T::esize;
|
||||
static void store(unsigned char* buffer, size_t idx, size_t psep, uint32_t v1, uint32_t v2,
|
||||
uint32_t v3)
|
||||
{
|
||||
T::store(buffer, idx, psep, v1, v2, v3);
|
||||
T::store(buffer, idx + T::esize * llen, psep, v1, v2, v3);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T, size_t llen>
|
||||
struct store_22
|
||||
{
|
||||
static const size_t esize = 2 * T::esize;
|
||||
static void store(unsigned char* buffer, size_t idx, size_t psep, uint32_t v1, uint32_t v2,
|
||||
uint32_t v3)
|
||||
{
|
||||
T::store(buffer, idx, psep, v1, v2, v3);
|
||||
T::store(buffer, idx + T::esize, psep, v1, v2, v3);
|
||||
T::store(buffer, idx + 2 * T::esize * llen, psep, v1, v2, v3);
|
||||
T::store(buffer, idx + 2 * T::esize * llen + T::esize, psep, v1, v2, v3);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct convert_11
|
||||
{
|
||||
static const size_t isize = 4;
|
||||
static const size_t esize = 2 * T::esize;
|
||||
static void convert(unsigned char* obuffer, size_t oidx, size_t psep, const unsigned char* ibuffer,
|
||||
size_t iidx)
|
||||
static const size_t esize = store::esize;
|
||||
static void convert(unsigned char* obuffer, size_t oidx, const unsigned char* ibuffer, size_t iidx,
|
||||
size_t psep)
|
||||
{
|
||||
//Compiler should be able to eliminate every if out of this.
|
||||
uint32_t Y = 0;
|
||||
uint32_t Cb = 0;
|
||||
uint32_t Cr = 0;
|
||||
TOYUV(ibuffer, iidx);
|
||||
T::store(obuffer, oidx, psep, Y, Cb, Cr);
|
||||
if(ioff1 > 0)
|
||||
TOYUV(ibuffer, iidx + ioff1 * 4);
|
||||
if(ioff2 > 0)
|
||||
TOYUV(ibuffer, iidx + ioff2 * 4);
|
||||
if(ioff3 > 0)
|
||||
TOYUV(ibuffer, iidx + ioff3 * 4);
|
||||
if(ioff1 > 0 && ioff2 > 0 && ioff3 > 0) {
|
||||
Y >>= 2;
|
||||
Cb >>= 2;
|
||||
Cr >>= 2;
|
||||
} else if(ioff1 > 0) {
|
||||
Y >>= 1;
|
||||
Cb >>= 1;
|
||||
Cr >>= 1;
|
||||
}
|
||||
store::store(obuffer, oidx, psep, Y, Cb, Cr);
|
||||
if(ooff1 > 0)
|
||||
store::store(obuffer, oidx + ooff1 * store::esize, psep, Y, Cb, Cr);
|
||||
if(ooff2 > 0)
|
||||
store::store(obuffer, oidx + ooff2 * store::esize, psep, Y, Cb, Cr);
|
||||
if(ooff3 > 0)
|
||||
store::store(obuffer, oidx + ooff3 * store::esize, psep, Y, Cb, Cr);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T, size_t s>
|
||||
struct convert_x_helper
|
||||
template<class proc, size_t lim, size_t igap, size_t ogap>
|
||||
struct loop
|
||||
{
|
||||
static void convert(unsigned char* obuffer, size_t oidx, size_t psep, const unsigned char* ibuffer,
|
||||
size_t iidx)
|
||||
static void f(unsigned char* buffer, const unsigned char* src, size_t psep)
|
||||
{
|
||||
uint32_t Y = 0;
|
||||
uint32_t Cb = 0;
|
||||
uint32_t Cr = 0;
|
||||
TOYUV(ibuffer, iidx);
|
||||
TOYUV(ibuffer, iidx + s);
|
||||
T::store(obuffer, oidx, psep, Y, Cb, Cr);
|
||||
for(size_t i = 0; i < lim; i++)
|
||||
proc::convert(buffer, proc::esize * ogap * i, src, 4 * igap * i, psep);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct convert_12
|
||||
//Render a line pair of YUV with 256x224/240
|
||||
template<class store>
|
||||
void render_yuv_256_240(unsigned char* buffer, const unsigned char* src, size_t psep, bool hires, bool interlaced)
|
||||
{
|
||||
static const size_t isize = 8;
|
||||
static const size_t esize = T::esize;
|
||||
static void convert(unsigned char* obuffer, size_t oidx, size_t psep, const unsigned char* ibuffer,
|
||||
size_t iidx)
|
||||
{
|
||||
convert_x_helper<T, 4>::convert(obuffer, oidx, psep, ibuffer, iidx);
|
||||
}
|
||||
};
|
||||
if(hires)
|
||||
if(interlaced)
|
||||
loop<loadstore<store, 1, 512, 513, 0, 0, 0>, 256, 2, 1>::f(buffer, src, psep);
|
||||
else
|
||||
loop<loadstore<store, 1, 0, 0, 0, 0, 0>, 256, 2, 1>::f(buffer, src, psep);
|
||||
else
|
||||
if(interlaced)
|
||||
loop<loadstore<store, 512, 0, 0, 0, 0, 0>, 256, 1, 1>::f(buffer, src, psep);
|
||||
else
|
||||
loop<loadstore<store, 0, 0, 0, 0, 0, 0>, 256, 1, 1>::f(buffer, src, psep);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
struct convert_21
|
||||
//Render a line pair of YUV with 512x224/240
|
||||
template<class store>
|
||||
void render_yuv_512_240(unsigned char* buffer, const unsigned char* src, size_t psep, bool hires, bool interlaced)
|
||||
{
|
||||
static const size_t isize = 4;
|
||||
static const size_t esize = T::esize;
|
||||
static void convert(unsigned char* obuffer, size_t oidx, size_t psep, const unsigned char* ibuffer,
|
||||
size_t iidx)
|
||||
{
|
||||
convert_x_helper<T, 2048>::convert(obuffer, oidx, psep, ibuffer, iidx);
|
||||
}
|
||||
};
|
||||
if(hires)
|
||||
if(interlaced)
|
||||
loop<loadstore<store, 512, 0, 0, 0, 0, 0>, 512, 1, 1>::f(buffer, src, psep);
|
||||
else
|
||||
loop<loadstore<store, 0, 0, 0, 0, 0, 0>, 512, 1, 1>::f(buffer, src, psep);
|
||||
else
|
||||
if(interlaced)
|
||||
loop<loadstore<store, 512, 0, 0, 1, 0, 0>, 256, 1, 2>::f(buffer, src, psep);
|
||||
else
|
||||
loop<loadstore<store, 0, 0, 0, 1, 0, 0>, 256, 1, 2>::f(buffer, src, psep);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
struct convert_22
|
||||
//Render a line pair of YUV with 256x448/480
|
||||
template<class store>
|
||||
void render_yuv_256_480(unsigned char* buffer, const unsigned char* src, size_t psep, bool hires, bool interlaced)
|
||||
{
|
||||
static const size_t isize = 8;
|
||||
static const size_t esize = T::esize;
|
||||
static void convert(unsigned char* obuffer, size_t oidx, size_t psep, const unsigned char* ibuffer,
|
||||
size_t iidx)
|
||||
{
|
||||
uint32_t Y = 0;
|
||||
uint32_t Cb = 0;
|
||||
uint32_t Cr = 0;
|
||||
TOYUV(ibuffer, iidx);
|
||||
TOYUV(ibuffer, iidx + 4);
|
||||
TOYUV(ibuffer, iidx + 2048);
|
||||
TOYUV(ibuffer, iidx + 2052);
|
||||
T::store(obuffer, oidx, psep, Y, Cb, Cr);
|
||||
}
|
||||
};
|
||||
if(hires)
|
||||
if(interlaced)
|
||||
loop<loadstore<store, 1, 0, 0, 0, 0, 0>, 256, 2, 1>::f(buffer, src, psep);
|
||||
else
|
||||
loop<loadstore<store, 1, 0, 0, 256, 0, 0>, 256, 2, 1>::f(buffer, src, psep);
|
||||
else
|
||||
if(interlaced)
|
||||
loop<loadstore<store, 0, 0, 0, 0, 0, 0>, 256, 1, 1>::f(buffer, src, psep);
|
||||
else
|
||||
loop<loadstore<store, 0, 0, 0, 256, 0, 0>, 256, 1, 1>::f(buffer, src, psep);
|
||||
}
|
||||
|
||||
template<typename T, size_t ents>
|
||||
struct convert_line
|
||||
//Render a line pair of YUV with 512x448/480
|
||||
template<class store>
|
||||
void render_yuv_512_480(unsigned char* buffer, const unsigned char* src, size_t psep, bool hires, bool interlaced)
|
||||
{
|
||||
static void convert(unsigned char* obuffer, size_t psep, const unsigned char* ibuffer)
|
||||
{
|
||||
for(unsigned i = 0; i < ents; i++)
|
||||
T::convert(obuffer, T::esize * i, psep, ibuffer, T::isize * i);
|
||||
}
|
||||
};
|
||||
if(hires)
|
||||
if(interlaced)
|
||||
loop<loadstore<store, 0, 0, 0, 0, 0, 0>, 512, 1, 1>::f(buffer, src, psep);
|
||||
else
|
||||
loop<loadstore<store, 0, 0, 0, 512, 0, 0>, 512, 1, 1>::f(buffer, src, psep);
|
||||
else
|
||||
if(interlaced)
|
||||
loop<loadstore<store, 0, 0, 0, 1, 0, 0>, 256, 1, 2>::f(buffer, src, psep);
|
||||
else
|
||||
loop<loadstore<store, 0, 0, 0, 1, 512, 513>, 256, 1, 2>::f(buffer, src, psep);
|
||||
}
|
||||
|
||||
#define RGB2YUV_SHIFT 14
|
||||
//Render a line pair of YUV with 512x448/480 fakeexpand
|
||||
template<class store>
|
||||
void render_yuv_fe(unsigned char* buffer, const unsigned char* src, size_t psep, bool hires, bool interlaced)
|
||||
{
|
||||
if(hires)
|
||||
if(interlaced)
|
||||
loop<loadstore<store, 0, 0, 0, 0, 0, 0>, 512, 1, 1>::f(buffer, src, psep);
|
||||
else
|
||||
loop<loadstore<store, 1, 0, 0, 1, 512, 513>, 256, 2, 2>::f(buffer, src, psep);
|
||||
else
|
||||
if(interlaced)
|
||||
loop<loadstore<store, 0, 0, 0, 1, 0, 0>, 256, 1, 2>::f(buffer, src, psep);
|
||||
else
|
||||
loop<loadstore<store, 0, 0, 0, 1, 256, 257>, 256, 1, 2>::f(buffer, src, psep);
|
||||
}
|
||||
|
||||
void init_matrix(double Kb, double Kr, bool fullrange)
|
||||
{
|
||||
|
@ -264,171 +249,6 @@ void load_rgb2yuv_matrix(uint32_t flags)
|
|||
}
|
||||
}
|
||||
|
||||
//Render a line pair of YUV.
|
||||
void render_yuv(unsigned char* buffer, const unsigned char* src, size_t psep, uint32_t flags, bool hires,
|
||||
bool interlaced)
|
||||
{
|
||||
unsigned c = 0;
|
||||
if(flags & FLAG_WIDTH)
|
||||
c |= 1;
|
||||
if(flags & FLAG_HEIGHT)
|
||||
c |= 2;
|
||||
if(hires)
|
||||
c |= 4;
|
||||
if(interlaced)
|
||||
c |= 8;
|
||||
if(flags & FLAG_8BIT)
|
||||
c |= 16;
|
||||
if(flags & FLAG_FAKENLARGE)
|
||||
c |= 35;
|
||||
switch(c) {
|
||||
case 0: { //256 x 224/240 -> 256 x 224/240 16 bit.
|
||||
convert_line<convert_11<store_11<store16<14>>>, 256>::convert(buffer, psep, src);
|
||||
break;
|
||||
}
|
||||
case 1: { //256 x 224/240 -> 512 x 224/240 16 bit.
|
||||
convert_line<convert_11<store_12<store16<14>>>, 256>::convert(buffer, psep, src);
|
||||
break;
|
||||
}
|
||||
case 2: { //256 x 224/240 -> 256 x 448/480 16 bit.
|
||||
convert_line<convert_11<store_21<store16<14>, 256>>, 256>::convert(buffer, psep, src);
|
||||
break;
|
||||
}
|
||||
case 3: case 35: { //256 x 224/240 -> 512 x 448/480 16 bit.
|
||||
convert_line<convert_11<store_22<store16<14>, 256>>, 256>::convert(buffer, psep, src);
|
||||
break;
|
||||
}
|
||||
case 4: { //512 x 224/240 -> 256 x 224/240 16 bit.
|
||||
convert_line<convert_12<store_11<store16<15>>>, 256>::convert(buffer, psep, src);
|
||||
break;
|
||||
}
|
||||
case 5: { //512 x 224/240 -> 512 x 224/240 16 bit.
|
||||
convert_line<convert_11<store_11<store16<14>>>, 512>::convert(buffer, psep, src);
|
||||
break;
|
||||
}
|
||||
case 6: { //512 x 224/240 -> 256 x 448/480 16 bit.
|
||||
convert_line<convert_12<store_21<store16<15>, 256>>, 256>::convert(buffer, psep, src);
|
||||
break;
|
||||
}
|
||||
case 7: { //512 x 224/240 -> 512 x 448/480 16 bit.
|
||||
convert_line<convert_11<store_21<store16<14>, 512>>, 512>::convert(buffer, psep, src);
|
||||
break;
|
||||
}
|
||||
case 39: { //512 x 224/240 -> 512 x 448/480 16 bit. FE
|
||||
convert_line<convert_12<store_22<store16<15>, 512>>, 256>::convert(buffer, psep, src);
|
||||
break;
|
||||
}
|
||||
case 8: { //256 x 448x480 -> 256 x 224/240 16 bit.
|
||||
convert_line<convert_21<store_11<store16<15>>>, 256>::convert(buffer, psep, src);
|
||||
break;
|
||||
}
|
||||
case 9: { //256 x 448x480 -> 512 x 224/240 16 bit.
|
||||
convert_line<convert_21<store_12<store16<15>>>, 256>::convert(buffer, psep, src);
|
||||
break;
|
||||
}
|
||||
case 10: { //256 x 448x480 -> 256 x 448/480 16 bit.
|
||||
convert_line<convert_11<store_11<store16<14>>>, 256>::convert(buffer, psep, src);
|
||||
convert_line<convert_11<store_11<store16<14>>>, 256>::convert(buffer + 512, psep, src + 2048);
|
||||
break;
|
||||
}
|
||||
case 11: case 43: { //256 x 448x480 -> 512 x 448/480 16 bit.
|
||||
convert_line<convert_11<store_12<store16<14>>>, 256>::convert(buffer, psep, src);
|
||||
convert_line<convert_11<store_12<store16<14>>>, 256>::convert(buffer + 1024, psep, src + 2048);
|
||||
break;
|
||||
}
|
||||
case 12: { //512 x 448x480 -> 256 x 224/240 16 bit.
|
||||
convert_line<convert_22<store_11<store16<16>>>, 256>::convert(buffer, psep, src);
|
||||
break;
|
||||
}
|
||||
case 13: { //512 x 448x480 -> 512 x 224/240 16 bit.
|
||||
convert_line<convert_21<store_11<store16<15>>>, 512>::convert(buffer, psep, src);
|
||||
break;
|
||||
}
|
||||
case 14: { //512 x 448x480 -> 256 x 448/480 16 bit.
|
||||
convert_line<convert_11<store_21<store16<14>, 256>>, 256>::convert(buffer, psep, src);
|
||||
convert_line<convert_11<store_21<store16<14>, 256>>, 256>::convert(buffer + 512, psep, src + 2048);
|
||||
break;
|
||||
}
|
||||
case 15: case 47: { //512 x 448x480 -> 512 x 448/480 16 bit.
|
||||
convert_line<convert_11<store_11<store16<14>>>, 512>::convert(buffer, psep, src);
|
||||
convert_line<convert_11<store_11<store16<14>>>, 512>::convert(buffer + 1024, psep, src + 2048);
|
||||
break;
|
||||
}
|
||||
case 16: { //256 x 224/240 -> 256 x 224/240 16 bit.
|
||||
convert_line<convert_11<store_11<store8<14>>>, 256>::convert(buffer, psep, src);
|
||||
break;
|
||||
}
|
||||
case 17: { //256 x 224/240 -> 512 x 224/240 16 bit.
|
||||
convert_line<convert_11<store_12<store8<14>>>, 256>::convert(buffer, psep, src);
|
||||
break;
|
||||
}
|
||||
case 18: { //256 x 224/240 -> 256 x 448/480 16 bit.
|
||||
convert_line<convert_11<store_21<store8<14>, 256>>, 256>::convert(buffer, psep, src);
|
||||
break;
|
||||
}
|
||||
case 19: case 51: { //256 x 224/240 -> 512 x 448/480 16 bit.
|
||||
convert_line<convert_11<store_22<store8<14>, 256>>, 256>::convert(buffer, psep, src);
|
||||
break;
|
||||
}
|
||||
case 20: { //512 x 224/240 -> 256 x 224/240 16 bit.
|
||||
convert_line<convert_12<store_11<store8<15>>>, 256>::convert(buffer, psep, src);
|
||||
break;
|
||||
}
|
||||
case 21: { //512 x 224/240 -> 512 x 224/240 16 bit.
|
||||
convert_line<convert_11<store_11<store8<14>>>, 512>::convert(buffer, psep, src);
|
||||
break;
|
||||
}
|
||||
case 22: { //512 x 224/240 -> 256 x 448/480 16 bit.
|
||||
convert_line<convert_12<store_21<store8<15>, 256>>, 256>::convert(buffer, psep, src);
|
||||
break;
|
||||
}
|
||||
case 23: { //512 x 224/240 -> 512 x 448/480 16 bit.
|
||||
convert_line<convert_11<store_21<store8<14>, 512>>, 512>::convert(buffer, psep, src);
|
||||
break;
|
||||
}
|
||||
case 55: { //512 x 224/240 -> 512 x 448/480 16 bit. FE
|
||||
convert_line<convert_12<store_22<store8<14>, 256>>, 256>::convert(buffer, psep, src);
|
||||
break;
|
||||
}
|
||||
case 24: { //256 x 448x480 -> 256 x 224/240 16 bit.
|
||||
convert_line<convert_21<store_11<store8<15>>>, 256>::convert(buffer, psep, src);
|
||||
break;
|
||||
}
|
||||
case 25: { //256 x 448x480 -> 512 x 224/240 16 bit.
|
||||
convert_line<convert_21<store_12<store8<15>>>, 256>::convert(buffer, psep, src);
|
||||
break;
|
||||
}
|
||||
case 26: { //256 x 448x480 -> 256 x 448/480 16 bit.
|
||||
convert_line<convert_11<store_11<store8<14>>>, 256>::convert(buffer, psep, src);
|
||||
convert_line<convert_11<store_11<store8<14>>>, 256>::convert(buffer + 256, psep, src + 2048);
|
||||
break;
|
||||
}
|
||||
case 27: case 59: { //256 x 448x480 -> 512 x 448/480 16 bit.
|
||||
convert_line<convert_11<store_12<store8<14>>>, 256>::convert(buffer, psep, src);
|
||||
convert_line<convert_11<store_12<store8<14>>>, 256>::convert(buffer + 512, psep, src + 2048);
|
||||
break;
|
||||
}
|
||||
case 28: { //512 x 448x480 -> 256 x 224/240 16 bit.
|
||||
convert_line<convert_22<store_11<store8<16>>>, 256>::convert(buffer, psep, src);
|
||||
break;
|
||||
}
|
||||
case 29: { //512 x 448x480 -> 512 x 224/240 16 bit.
|
||||
convert_line<convert_21<store_11<store8<15>>>, 512>::convert(buffer, psep, src);
|
||||
break;
|
||||
}
|
||||
case 30: { //512 x 448x480 -> 256 x 448/480 16 bit.
|
||||
convert_line<convert_11<store_21<store8<14>, 256>>, 256>::convert(buffer, psep, src);
|
||||
convert_line<convert_11<store_21<store8<14>, 256>>, 256>::convert(buffer + 256, psep, src + 2048);
|
||||
break;
|
||||
}
|
||||
case 31: case 63: { //512 x 448x480 -> 512 x 448/480 16 bit.
|
||||
convert_line<convert_11<store_11<store8<14>>>, 512>::convert(buffer, psep, src);
|
||||
convert_line<convert_11<store_11<store8<14>>>, 512>::convert(buffer + 512, psep, src + 2048);
|
||||
break;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
uint64_t double_to_ieeefp(double v)
|
||||
{
|
||||
unsigned mag = 1023;
|
||||
|
@ -451,8 +271,46 @@ uint64_t double_to_ieeefp(double v)
|
|||
return v2;
|
||||
}
|
||||
|
||||
void sdump2sox(std::istream& in, std::ostream& yout, std::ostream& sout, uint32_t flags)
|
||||
void sdump2sox(std::istream& in, std::ostream& yout, std::ostream& sout, std::ostream& tout, int32_t flags)
|
||||
{
|
||||
unsigned elided = 0;
|
||||
uint64_t ftcw = 0;
|
||||
uint64_t ftcn = 0;
|
||||
if(flags & FLAG_DEDUP)
|
||||
tout << "# timecode format v2" << std::endl;
|
||||
void (*render_yuv)(unsigned char* buffer, const unsigned char* src, size_t psep, bool hires, bool interlaced);
|
||||
switch(flags & (FLAG_WIDTH | FLAG_HEIGHT | FLAG_8BIT | FLAG_FAKENLARGE)) {
|
||||
case 0:
|
||||
render_yuv = render_yuv_256_240<store16>;
|
||||
break;
|
||||
case FLAG_WIDTH:
|
||||
render_yuv = render_yuv_512_240<store16>;
|
||||
break;
|
||||
case FLAG_HEIGHT:
|
||||
render_yuv = render_yuv_256_480<store16>;
|
||||
break;
|
||||
case FLAG_WIDTH | FLAG_HEIGHT:
|
||||
render_yuv = render_yuv_512_480<store16>;
|
||||
break;
|
||||
case FLAG_WIDTH | FLAG_HEIGHT | FLAG_FAKENLARGE:
|
||||
render_yuv = render_yuv_fe<store16>;
|
||||
break;
|
||||
case FLAG_8BIT:
|
||||
render_yuv = render_yuv_256_240<store8>;
|
||||
break;
|
||||
case FLAG_WIDTH | FLAG_8BIT:
|
||||
render_yuv = render_yuv_512_240<store8>;
|
||||
break;
|
||||
case FLAG_HEIGHT | FLAG_8BIT:
|
||||
render_yuv = render_yuv_256_480<store8>;
|
||||
break;
|
||||
case FLAG_WIDTH | FLAG_HEIGHT | FLAG_8BIT:
|
||||
render_yuv = render_yuv_512_480<store8>;
|
||||
break;
|
||||
case FLAG_WIDTH | FLAG_HEIGHT | FLAG_FAKENLARGE | FLAG_8BIT:
|
||||
render_yuv = render_yuv_fe<store8>;
|
||||
break;
|
||||
}
|
||||
unsigned char header[12];
|
||||
in.read(reinterpret_cast<char*>(header), 12);
|
||||
if(!in)
|
||||
|
@ -526,17 +384,18 @@ void sdump2sox(std::istream& in, std::ostream& yout, std::ostream& sout, uint32_
|
|||
continue;
|
||||
if(!pal & physline >= 224)
|
||||
continue;
|
||||
render_yuv(yuv_buffer + physline * lsep, buf, psep, flags, hires, interlaced);
|
||||
render_yuv(yuv_buffer + physline * lsep, buf, psep, hires, interlaced);
|
||||
physline++;
|
||||
}
|
||||
if(pal) {
|
||||
//Render a black line to pad the image.
|
||||
memset(buf, 0, 4096);
|
||||
render_yuv(yuv_buffer + 239 * lsep, buf, psep, flags, hires, interlaced);
|
||||
render_yuv(yuv_buffer + 239 * lsep, buf, psep, hires, interlaced);
|
||||
}
|
||||
size_t yuvsize = 3 * psep;
|
||||
unsigned times = 1;
|
||||
if((flags & FLAG_FRAMERATE) == 0 && !is_pal && interlaced) {
|
||||
//If FLAG_DEDUP is set, no frames are added or dropped to match timecodes.
|
||||
if((flags & (FLAG_FRAMERATE | FLAG_DEDUP)) == 0 && !is_pal && interlaced) {
|
||||
//This uses 357368 TU instead of 357366 TU.
|
||||
//-> Every 178683rd frame is duplicated.
|
||||
if(wrongrate == 178682) {
|
||||
|
@ -545,7 +404,7 @@ void sdump2sox(std::istream& in, std::ostream& yout, std::ostream& sout, uint32_
|
|||
} else
|
||||
wrongrate++;
|
||||
}
|
||||
if((flags & FLAG_FRAMERATE) != 0 && !is_pal && !interlaced) {
|
||||
if((flags & (FLAG_FRAMERATE | FLAG_DEDUP)) == FLAG_FRAMERATE && !is_pal && !interlaced) {
|
||||
//This uses 357366 TU instead of 357368 TU.
|
||||
//-> Every 178684th frame is dropped.
|
||||
if(wrongrate == 178683) {
|
||||
|
@ -554,12 +413,30 @@ void sdump2sox(std::istream& in, std::ostream& yout, std::ostream& sout, uint32_
|
|||
} else
|
||||
wrongrate++;
|
||||
}
|
||||
if(flags & FLAG_DEDUP) {
|
||||
if(memcmp(old_yuv_buffer, yuv_buffer, yuvsize)) {
|
||||
memcpy(old_yuv_buffer, yuv_buffer, yuvsize);
|
||||
elided = 0;
|
||||
} else
|
||||
elided = (++elided) % MAX_DEDUP;
|
||||
if(elided)
|
||||
times = 0;
|
||||
else
|
||||
tout << ftcw << std::endl;
|
||||
}
|
||||
for(unsigned k = 0; k < times; k++)
|
||||
yout.write(reinterpret_cast<char*>(yuv_buffer), yuvsize);
|
||||
if(!yout)
|
||||
throw std::runtime_error("Can't write frame");
|
||||
frames += times;
|
||||
lf = true;
|
||||
uint64_t tcc = is_pal ? 425568000 : (interlaced ? 357368000 : 357366000);
|
||||
ftcw = ftcw + tcc / cpurate;
|
||||
ftcn = ftcn + tcc % cpurate;
|
||||
if(ftcn >= cpurate) {
|
||||
ftcw++;
|
||||
ftcn -= cpurate;
|
||||
}
|
||||
} else if(cmd == 16) {
|
||||
//Sound packet. Interesting.
|
||||
unsigned char ibuf[4];
|
||||
|
@ -622,11 +499,13 @@ void sdump2sox(std::istream& in, std::ostream& yout, std::ostream& sout, uint32_
|
|||
|
||||
void syntax()
|
||||
{
|
||||
std::cerr << "Syntax: sdump2sox [<options>] <input-file> <yuv-output-file> <sox-output-file>" << std::endl;
|
||||
std::cerr << "Syntax: sdump2sox [<options>] <input-file> <yuv-output-file> <sox-output-file> "
|
||||
<< "[<tc-output-file>]" << std::endl;
|
||||
std::cerr << "-W\tDump 512-wide instead of 256-wide." << std::endl;
|
||||
std::cerr << "-H\tDump 448/480-high instead of 224/240-high." << std::endl;
|
||||
std::cerr << "-D\tDedup the output (also uses exact timecodes)." << std::endl;
|
||||
std::cerr << "-h\tDump 512x448/480, doing blending for 512x224/240." << std::endl;
|
||||
std::cerr << "-F\tDump at interlaced framerate instead of non-interlaced." << std::endl;
|
||||
std::cerr << "-F\tDump at interlaced framerate instead of non-interlaced (no effect if dedup)." << std::endl;
|
||||
std::cerr << "-f\tDump using full range instead of TV range." << std::endl;
|
||||
std::cerr << "-7\tDump using ITU.709 instead of ITU.601." << std::endl;
|
||||
std::cerr << "-2\tDump using SMPTE-240M instead of ITU.601." << std::endl;
|
||||
|
@ -643,6 +522,7 @@ int main(int argc, char** argv)
|
|||
uint32_t idx1 = 0;
|
||||
uint32_t idx2 = 0;
|
||||
uint32_t idx3 = 0;
|
||||
uint32_t idx4 = 0;
|
||||
for(unsigned i = 1; i < argc; i++) {
|
||||
if(argv[i][0] == '-')
|
||||
for(unsigned j = 1; argv[i][j]; j++)
|
||||
|
@ -656,6 +536,9 @@ int main(int argc, char** argv)
|
|||
case 'F':
|
||||
flags |= FLAG_FRAMERATE;
|
||||
break;
|
||||
case 'D':
|
||||
flags |= FLAG_DEDUP;
|
||||
break;
|
||||
case 'f':
|
||||
flags |= FLAG_FULLRANGE;
|
||||
break;
|
||||
|
@ -689,11 +572,17 @@ int main(int argc, char** argv)
|
|||
idx2 = i;
|
||||
else if(!idx3)
|
||||
idx3 = i;
|
||||
else if(!idx4)
|
||||
idx4 = i;
|
||||
else {
|
||||
syntax();
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if(idx4 && !(flags & FLAG_DEDUP)) {
|
||||
syntax();
|
||||
return 1;
|
||||
}
|
||||
std::ifstream in(argv[idx1], std::ios::in | std::ios::binary);
|
||||
if(!in) {
|
||||
std::cerr << "Error: Can't open '" << argv[idx1] << "'" << std::endl;
|
||||
|
@ -709,16 +598,29 @@ int main(int argc, char** argv)
|
|||
std::cerr << "Error: Can't open '" << argv[idx3] << "'" << std::endl;
|
||||
return 2;
|
||||
}
|
||||
std::ofstream tout;
|
||||
if(flags & FLAG_DEDUP) {
|
||||
if(idx4)
|
||||
tout.open(argv[idx4], std::ios::out);
|
||||
else
|
||||
tout.open(argv[idx2] + std::string(".tc"), std::ios::out);
|
||||
if(!tout) {
|
||||
std::cerr << "Error: Can't open '" << argv[idx2] << ".tc'" << std::endl;
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
try {
|
||||
sdump2sox(in, yout, sout, flags);
|
||||
sdump2sox(in, yout, sout, tout, flags);
|
||||
in.close();
|
||||
yout.close();
|
||||
sout.close();
|
||||
tout.close();
|
||||
} catch(std::exception& e) {
|
||||
std::cerr << "Error: " << e.what() << std::endl;
|
||||
in.close();
|
||||
yout.close();
|
||||
sout.close();
|
||||
tout.close();
|
||||
return 3;
|
||||
}
|
||||
return 0;
|
||||
|
|
Loading…
Add table
Reference in a new issue