Remove long-unmaintained SNES-specific dump format
This commit is contained in:
parent
2995be7f12
commit
b9fedf0dde
2 changed files with 0 additions and 1157 deletions
|
@ -1,922 +0,0 @@
|
|||
#include <cstdint>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
#include <cstring>
|
||||
|
||||
#define FLAG_WIDTH 1
|
||||
#define FLAG_HEIGHT 2
|
||||
#define FLAG_FRAMERATE 4
|
||||
#define FLAG_FULLRANGE 8
|
||||
#define FLAG_ITU601 0
|
||||
#define FLAG_ITU709 16
|
||||
#define FLAG_SMPTE240M 32
|
||||
#define FLAG_CS_MASK 48
|
||||
#define FLAG_8BIT 64
|
||||
#define FLAG_FAKENLARGE 128
|
||||
#define FLAG_DEDUP 256
|
||||
#define FLAG_OFFSET2 512
|
||||
#define FLAG_10FRAMES 1024
|
||||
#define FLAG_AR_CORRECT 2048
|
||||
|
||||
#define CMD_HIRES 1
|
||||
#define CMD_INTERLACED 2
|
||||
#define CMD_OVERSCAN 4
|
||||
#define CMD_PAL 8
|
||||
|
||||
#define MAX_DEDUP 9
|
||||
|
||||
//This buffer needs to be big enough to store 640x480 16-bit YCbCr 4:4:4 (6 bytes per pixel) image.
|
||||
#define MAXYUVSIZE (640 * 480 * 6)
|
||||
unsigned char yuv_buffer[MAXYUVSIZE];
|
||||
unsigned char old_yuv_buffer[MAXYUVSIZE];
|
||||
|
||||
//30 bit values.
|
||||
uint32_t ymatrix[0x80000];
|
||||
uint32_t cbmatrix[0x80000];
|
||||
uint32_t crmatrix[0x80000];
|
||||
|
||||
|
||||
#define TOYUV(src, idx) do {\
|
||||
uint32_t c = (static_cast<uint32_t>(src[(idx) + 0]) << 24) |\
|
||||
(static_cast<uint32_t>(src[(idx) + 1]) << 16) |\
|
||||
(static_cast<uint32_t>(src[(idx) + 2]) << 8) |\
|
||||
static_cast<uint32_t>(src[(idx) + 3]);\
|
||||
Y += ymatrix[c & 0x7FFFF];\
|
||||
Cb += cbmatrix[c & 0x7FFFF];\
|
||||
Cr += crmatrix[c & 0x7FFFF];\
|
||||
} while(0)
|
||||
|
||||
#define RGB2YUV_SHIFT 14
|
||||
|
||||
class sox_output
|
||||
{
|
||||
public:
|
||||
sox_output(std::ostream& soxs, uint32_t apurate, bool silence2);
|
||||
void close();
|
||||
void add_sample(unsigned char* buf);
|
||||
uint64_t get_samples();
|
||||
private:
|
||||
std::ostream& strm;
|
||||
uint64_t samples;
|
||||
};
|
||||
|
||||
class sdmp_input_stream
|
||||
{
|
||||
public:
|
||||
sdmp_input_stream(std::istream& sdmp);
|
||||
uint32_t get_cpurate();
|
||||
uint32_t get_apurate();
|
||||
int read_command();
|
||||
void read_linepair(unsigned char* buffer);
|
||||
void copy_audio_sample(sox_output& audio_out);
|
||||
private:
|
||||
std::istream& strm;
|
||||
uint32_t cpurate;
|
||||
uint32_t apurate;
|
||||
};
|
||||
|
||||
class time_tracker
|
||||
{
|
||||
public:
|
||||
time_tracker(uint32_t _cpurate);
|
||||
void add_2s();
|
||||
void advance(bool pal, bool interlaced);
|
||||
uint64_t get_ts();
|
||||
private:
|
||||
uint32_t cpurate;
|
||||
uint64_t w;
|
||||
uint64_t n;
|
||||
};
|
||||
|
||||
class dup_tracker
|
||||
{
|
||||
public:
|
||||
dup_tracker(std::ostream& _tcfile, uint32_t _flags);
|
||||
uint32_t process(unsigned char* buffer, size_t bufsize, int pkt_type, time_tracker& ts);
|
||||
private:
|
||||
std::ostream& tcfile;
|
||||
uint32_t flags;
|
||||
uint32_t counter;
|
||||
};
|
||||
|
||||
|
||||
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 >> RGB2YUV_SHIFT);
|
||||
*reinterpret_cast<uint16_t*>(buffer + idx + psep) = (v2 >> RGB2YUV_SHIFT);
|
||||
*reinterpret_cast<uint16_t*>(buffer + idx + 2 * psep) = (v3 >> RGB2YUV_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 >> (RGB2YUV_SHIFT + 8));
|
||||
buffer[idx + psep] = (v2 >> (RGB2YUV_SHIFT + 8));
|
||||
buffer[idx + 2 * psep] = (v3 >> (RGB2YUV_SHIFT + 8));
|
||||
}
|
||||
};
|
||||
|
||||
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 = 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);
|
||||
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<class proc, size_t lim, size_t igap, size_t ogap>
|
||||
struct loop
|
||||
{
|
||||
static void f(unsigned char* buffer, const unsigned char* src, size_t psep)
|
||||
{
|
||||
for(size_t i = 0; i < lim; i++)
|
||||
proc::convert(buffer, proc::esize * ogap * i, src, 4 * igap * i, psep);
|
||||
}
|
||||
};
|
||||
|
||||
//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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
//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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
//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)
|
||||
{
|
||||
if(hires)
|
||||
if(interlaced) {
|
||||
loop<loadstore<store, 1, 0, 0, 0, 0, 0>, 256, 2, 1>::f(buffer, src, psep);
|
||||
loop<loadstore<store, 1, 0, 0, 0, 0, 0>, 256, 2, 1>::f(buffer + 256 * store::esize,
|
||||
src + 2048, 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);
|
||||
loop<loadstore<store, 0, 0, 0, 0, 0, 0>, 256, 1, 1>::f(buffer + 256 * store::esize,
|
||||
src + 2048, psep);
|
||||
} else
|
||||
loop<loadstore<store, 0, 0, 0, 256, 0, 0>, 256, 1, 1>::f(buffer, src, psep);
|
||||
}
|
||||
|
||||
//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)
|
||||
{
|
||||
if(hires)
|
||||
if(interlaced) {
|
||||
loop<loadstore<store, 0, 0, 0, 0, 0, 0>, 512, 1, 1>::f(buffer, src, psep);
|
||||
loop<loadstore<store, 0, 0, 0, 0, 0, 0>, 512, 1, 1>::f(buffer + 512 * store::esize,
|
||||
src + 2048, 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);
|
||||
loop<loadstore<store, 0, 0, 0, 1, 0, 0>, 256, 1, 2>::f(buffer + 512 * store::esize,
|
||||
src + 2048, psep);
|
||||
} else
|
||||
loop<loadstore<store, 0, 0, 0, 1, 512, 513>, 256, 1, 2>::f(buffer, src, psep);
|
||||
}
|
||||
|
||||
//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);
|
||||
loop<loadstore<store, 0, 0, 0, 0, 0, 0>, 512, 1, 1>::f(buffer + 512 * store::esize,
|
||||
src + 2048, 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);
|
||||
loop<loadstore<store, 0, 0, 0, 1, 0, 0>, 256, 1, 2>::f(buffer + 512 * store::esize,
|
||||
src + 2048, psep);
|
||||
} else
|
||||
loop<loadstore<store, 0, 0, 0, 1, 256, 257>, 256, 1, 2>::f(buffer, src, psep);
|
||||
}
|
||||
|
||||
typedef void (*render_yuv_t)(unsigned char* buffer, const unsigned char* src, size_t psep, bool hires,
|
||||
bool interlaced);
|
||||
|
||||
render_yuv_t get_renderer_for(int32_t flags)
|
||||
{
|
||||
int32_t mode = flags & (FLAG_WIDTH | FLAG_HEIGHT | FLAG_8BIT | FLAG_FAKENLARGE);
|
||||
if(mode == 0)
|
||||
return render_yuv_256_240<store16>;
|
||||
if(mode == FLAG_WIDTH)
|
||||
return render_yuv_512_240<store16>;
|
||||
if(mode == FLAG_HEIGHT)
|
||||
return render_yuv_256_480<store16>;
|
||||
if(mode == (FLAG_WIDTH | FLAG_HEIGHT))
|
||||
return render_yuv_512_480<store16>;
|
||||
if(mode == (FLAG_WIDTH | FLAG_HEIGHT | FLAG_FAKENLARGE))
|
||||
return render_yuv_fe<store16>;
|
||||
if(mode == FLAG_8BIT)
|
||||
return render_yuv_256_240<store8>;
|
||||
if(mode == (FLAG_WIDTH | FLAG_8BIT))
|
||||
return render_yuv_512_240<store8>;
|
||||
if(mode == (FLAG_HEIGHT | FLAG_8BIT))
|
||||
return render_yuv_256_480<store8>;
|
||||
if(mode == (FLAG_WIDTH | FLAG_HEIGHT | FLAG_8BIT))
|
||||
return render_yuv_512_480<store8>;
|
||||
if(mode == (FLAG_WIDTH | FLAG_HEIGHT | FLAG_FAKENLARGE | FLAG_8BIT))
|
||||
return render_yuv_fe<store8>;
|
||||
throw std::runtime_error("get_renderer_for: Unknown flags combination");
|
||||
}
|
||||
|
||||
void init_matrix(double Kb, double Kr, bool fullrange)
|
||||
{
|
||||
double RY = Kr;
|
||||
double GY = 1 - Kr - Kb;
|
||||
double BY = Kb;
|
||||
double RPb = -0.5 * Kr / (1 - Kb);
|
||||
double GPb = -0.5 * (1 - Kr - Kb) / (1 - Kb);
|
||||
double BPb = 0.5;
|
||||
double RPr = 0.5;
|
||||
double GPr = -0.5 * (1 - Kr - Kb) / (1 - Kr);
|
||||
double BPr = -0.5 * Kb / (1 - Kr);
|
||||
for(uint32_t i = 0; i < 0x80000; i++) {
|
||||
uint32_t l = 1 + ((i >> 15) & 0xF);
|
||||
//Range of (r,g,b) is 0...496.
|
||||
uint32_t r = (l * ((i >> 0) & 0x1F));
|
||||
uint32_t g = (l * ((i >> 5) & 0x1F));
|
||||
uint32_t b = (l * ((i >> 10) & 0x1F));
|
||||
double Y = (RY * r + GY * g + BY * b) / 496 * (fullrange ? 255 : 219) + (fullrange ? 0 : 16);
|
||||
double Cb = (RPb * r + GPb * g + BPb * b) / 496 * (fullrange ? 255 : 224) + 128;
|
||||
double Cr = (RPr * r + GPr * g + BPr * b) / 496 * (fullrange ? 255 : 224) + 128;
|
||||
ymatrix[i] = static_cast<uint32_t>(Y * 4194304 + 0.5);
|
||||
cbmatrix[i] = static_cast<uint32_t>(Cb * 4194304 + 0.5);
|
||||
crmatrix[i] = static_cast<uint32_t>(Cr * 4194304 + 0.5);
|
||||
}
|
||||
}
|
||||
|
||||
//Load RGB to YUV conversion matrix.
|
||||
void load_rgb2yuv_matrix(uint32_t flags)
|
||||
{
|
||||
switch(flags & (FLAG_CS_MASK))
|
||||
{
|
||||
case FLAG_ITU601:
|
||||
init_matrix(0.114, 0.229, flags & FLAG_FULLRANGE);
|
||||
break;
|
||||
case FLAG_ITU709:
|
||||
init_matrix(0.0722, 0.2126, flags & FLAG_FULLRANGE);
|
||||
break;
|
||||
case FLAG_SMPTE240M:
|
||||
init_matrix(0.087, 0.212, flags & FLAG_FULLRANGE);
|
||||
break;
|
||||
default:
|
||||
init_matrix(0.114, 0.229, flags & FLAG_FULLRANGE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t double_to_ieeefp(double v)
|
||||
{
|
||||
unsigned mag = 1023;
|
||||
while(v >= 2) {
|
||||
mag++;
|
||||
v /= 2;
|
||||
}
|
||||
while(v < 1) {
|
||||
mag--;
|
||||
v *= 2;
|
||||
}
|
||||
uint64_t v2 = mag;
|
||||
v -= 1;
|
||||
for(unsigned i = 0; i < 52; i++) {
|
||||
v *= 2;
|
||||
v2 = 2 * v2 + ((v >= 1) ? 1 : 0);
|
||||
if(v >= 1)
|
||||
v -= 1;
|
||||
}
|
||||
return v2;
|
||||
}
|
||||
|
||||
|
||||
sox_output::sox_output(std::ostream& soxs, uint32_t apurate, bool silence2)
|
||||
: strm(soxs)
|
||||
{
|
||||
uint64_t sndrateR = double_to_ieeefp(static_cast<double>(apurate) / 768.0);
|
||||
unsigned char sox_header[32] = {0};
|
||||
sox_header[0] = 0x2E; //Magic
|
||||
sox_header[1] = 0x53; //Magic
|
||||
sox_header[2] = 0x6F; //Magic
|
||||
sox_header[3] = 0x58; //Magic
|
||||
sox_header[4] = 0x1C; //Magic
|
||||
sox_header[16] = sndrateR;
|
||||
sox_header[17] = sndrateR >> 8;
|
||||
sox_header[18] = sndrateR >> 16;
|
||||
sox_header[19] = sndrateR >> 24;
|
||||
sox_header[20] = sndrateR >> 32;
|
||||
sox_header[21] = sndrateR >> 40;
|
||||
sox_header[22] = sndrateR >> 48;
|
||||
sox_header[23] = sndrateR >> 56;
|
||||
sox_header[24] = 2;
|
||||
strm.write(reinterpret_cast<char*>(sox_header), 32);
|
||||
if(!strm)
|
||||
throw std::runtime_error("Can't write audio header");
|
||||
samples = 0;
|
||||
if(silence2) {
|
||||
uint64_t nullsamples = apurate / 384;
|
||||
samples = nullsamples;
|
||||
const size_t bufsz = 512;
|
||||
char nbuffer[8 * bufsz] = {0};
|
||||
while(nullsamples > bufsz) {
|
||||
strm.write(nbuffer, 8 * bufsz);
|
||||
nullsamples -= bufsz;
|
||||
}
|
||||
strm.write(nbuffer, 8 * nullsamples);
|
||||
if(!strm)
|
||||
throw std::runtime_error("Can't write 2 second silence");
|
||||
}
|
||||
}
|
||||
|
||||
void sox_output::close()
|
||||
{
|
||||
//Sox internally multiplies sample count by channel count.
|
||||
unsigned char sox_header[8];
|
||||
sox_header[0] = samples << 1;
|
||||
sox_header[1] = samples >> 7;
|
||||
sox_header[2] = samples >> 15;
|
||||
sox_header[3] = samples >> 23;
|
||||
sox_header[4] = samples >> 31;
|
||||
sox_header[5] = samples >> 39;
|
||||
sox_header[6] = samples >> 47;
|
||||
sox_header[7] = samples >> 55;
|
||||
strm.seekp(8, std::ios::beg);
|
||||
if(!strm)
|
||||
throw std::runtime_error("Can't seek to fix .sox header");
|
||||
strm.write(reinterpret_cast<char*>(sox_header), 8);
|
||||
if(!strm)
|
||||
throw std::runtime_error("Can't fix audio header");
|
||||
}
|
||||
|
||||
void sox_output::add_sample(unsigned char* buf)
|
||||
{
|
||||
strm.write(reinterpret_cast<char*>(buf), 8);
|
||||
if(!strm)
|
||||
throw std::runtime_error("Can't write audio sample");
|
||||
samples++;
|
||||
}
|
||||
|
||||
uint64_t sox_output::get_samples()
|
||||
{
|
||||
return samples;
|
||||
}
|
||||
|
||||
sdmp_input_stream::sdmp_input_stream(std::istream& sdmp)
|
||||
: strm(sdmp)
|
||||
{
|
||||
unsigned char header[12];
|
||||
strm.read(reinterpret_cast<char*>(header), 12);
|
||||
if(!strm)
|
||||
throw std::runtime_error("Can't read sdump header");
|
||||
if(header[0] != 'S' || header[1] != 'D' || header[2] != 'M' || header[3] != 'P')
|
||||
throw std::runtime_error("Bad sdump magic");
|
||||
cpurate = (static_cast<uint32_t>(header[4]) << 24) |
|
||||
(static_cast<uint32_t>(header[5]) << 16) |
|
||||
(static_cast<uint32_t>(header[6]) << 8) |
|
||||
static_cast<uint32_t>(header[7]);
|
||||
apurate = (static_cast<uint32_t>(header[8]) << 24) |
|
||||
(static_cast<uint32_t>(header[9]) << 16) |
|
||||
(static_cast<uint32_t>(header[10]) << 8) |
|
||||
static_cast<uint32_t>(header[11]);
|
||||
}
|
||||
|
||||
uint32_t sdmp_input_stream::get_cpurate()
|
||||
{
|
||||
return cpurate;
|
||||
}
|
||||
|
||||
uint32_t sdmp_input_stream::get_apurate()
|
||||
{
|
||||
return apurate;
|
||||
}
|
||||
|
||||
int sdmp_input_stream::read_command()
|
||||
{
|
||||
unsigned char cmd;
|
||||
strm >> cmd;
|
||||
if(!strm)
|
||||
return -1;
|
||||
return cmd;
|
||||
}
|
||||
|
||||
void sdmp_input_stream::read_linepair(unsigned char* buffer)
|
||||
{
|
||||
strm.read(reinterpret_cast<char*>(buffer), 4096);
|
||||
if(!strm)
|
||||
throw std::runtime_error("Can't read picture payload");
|
||||
}
|
||||
|
||||
void sdmp_input_stream::copy_audio_sample(sox_output& audio_out)
|
||||
{
|
||||
unsigned char ibuf[4];
|
||||
unsigned char obuf[8];
|
||||
strm.read(reinterpret_cast<char*>(ibuf), 4);
|
||||
if(!strm)
|
||||
throw std::runtime_error("Can't read sound packet payload");
|
||||
obuf[0] = 0;
|
||||
obuf[1] = 0;
|
||||
obuf[2] = ibuf[1];
|
||||
obuf[3] = ibuf[0];
|
||||
obuf[4] = 0;
|
||||
obuf[5] = 0;
|
||||
obuf[6] = ibuf[3];
|
||||
obuf[7] = ibuf[2];
|
||||
audio_out.add_sample(obuf);
|
||||
}
|
||||
|
||||
time_tracker::time_tracker(uint32_t _cpurate)
|
||||
{
|
||||
cpurate = _cpurate;
|
||||
w = n = 0;
|
||||
}
|
||||
|
||||
void time_tracker::add_2s()
|
||||
{
|
||||
w += 2000;
|
||||
}
|
||||
|
||||
void time_tracker::advance(bool pal, bool interlaced)
|
||||
{
|
||||
uint64_t tcc = pal ? 425568000 : (interlaced ? 357368000 : 357366000);
|
||||
w += tcc / cpurate;
|
||||
n += tcc % cpurate;
|
||||
w += n / cpurate;
|
||||
n %= cpurate;
|
||||
}
|
||||
|
||||
uint64_t time_tracker::get_ts()
|
||||
{
|
||||
return w;
|
||||
}
|
||||
|
||||
dup_tracker::dup_tracker(std::ostream& _tcfile, uint32_t _flags)
|
||||
: tcfile(_tcfile)
|
||||
{
|
||||
flags = _flags;
|
||||
counter = 0;
|
||||
}
|
||||
|
||||
uint32_t dup_tracker::process(unsigned char* buffer, size_t bufsize, int pkt_type, time_tracker& ts)
|
||||
{
|
||||
if(flags & FLAG_DEDUP) {
|
||||
if(memcmp(buffer, old_yuv_buffer, bufsize)) {
|
||||
memcpy(old_yuv_buffer, buffer, bufsize);
|
||||
counter = 0;
|
||||
} else
|
||||
counter = (counter + 1) % MAX_DEDUP;
|
||||
if(counter)
|
||||
return 0;
|
||||
else {
|
||||
tcfile << ts.get_ts() << std::endl;
|
||||
if(!tcfile)
|
||||
throw std::runtime_error("Can't write frame timestamp");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if(pkt_type & CMD_PAL)
|
||||
return 1; //No wrong framerate correction in PAL mode.
|
||||
bool framerate_flag = (flags & FLAG_FRAMERATE);
|
||||
bool interlaced = (pkt_type & CMD_INTERLACED);
|
||||
if(!framerate_flag && interlaced) {
|
||||
//This uses 357368 TU instead of 357366 TU.
|
||||
//-> Every 178683rd frame is duplicated.
|
||||
counter = (counter + 1) % 178683;
|
||||
if(counter)
|
||||
return 2;
|
||||
}
|
||||
if(framerate_flag && !interlaced) {
|
||||
//This uses 357366 TU instead of 357368 TU.
|
||||
//-> Every 178684th frame is dropped.
|
||||
counter = (counter + 1) % 178684;
|
||||
if(!counter)
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
size_t calculate_line_separation(int32_t flags, int pkt_type)
|
||||
{
|
||||
size_t s = 256;
|
||||
if(flags & FLAG_AR_CORRECT)
|
||||
if(pkt_type & CMD_PAL)
|
||||
s = (flags & FLAG_WIDTH) ? 640 : 320;
|
||||
else
|
||||
s = (flags & FLAG_WIDTH) ? 598 : 298;
|
||||
else if(flags & FLAG_WIDTH)
|
||||
s *= 2;
|
||||
if(flags & FLAG_HEIGHT)
|
||||
s *= 2;
|
||||
if(!(flags & FLAG_8BIT))
|
||||
s *= 2;
|
||||
return s;
|
||||
}
|
||||
|
||||
size_t calculate_plane_separation(int32_t flags, int pkt_type)
|
||||
{
|
||||
size_t s = calculate_line_separation(flags, pkt_type);
|
||||
if(pkt_type & CMD_PAL)
|
||||
s *= 240;
|
||||
else
|
||||
s *= 224;
|
||||
return s;
|
||||
}
|
||||
|
||||
bool is_renderable_line(int pkt_type, unsigned line_pair, unsigned rendered)
|
||||
{
|
||||
switch(pkt_type & (CMD_OVERSCAN | CMD_PAL)) {
|
||||
case 0:
|
||||
return (line_pair >= 9 && rendered < 224);
|
||||
case CMD_OVERSCAN:
|
||||
return (line_pair >= 16 && rendered < 224);
|
||||
case CMD_PAL:
|
||||
return (line_pair >= 1 && rendered < 239);
|
||||
case CMD_PAL | CMD_INTERLACED:
|
||||
return (line_pair >= 9 && rendered < 239);
|
||||
};
|
||||
return false;
|
||||
}
|
||||
|
||||
void lanczos_256_298_16(unsigned short* dst, unsigned short* src);
|
||||
void lanczos_256_320_16(unsigned short* dst, unsigned short* src);
|
||||
void lanczos_512_598_16(unsigned short* dst, unsigned short* src);
|
||||
void lanczos_512_640_16(unsigned short* dst, unsigned short* src);
|
||||
void lanczos_256_298_8(unsigned char* dst, unsigned char* src);
|
||||
void lanczos_256_320_8(unsigned char* dst, unsigned char* src);
|
||||
void lanczos_512_598_8(unsigned char* dst, unsigned char* src);
|
||||
void lanczos_512_640_8(unsigned char* dst, unsigned char* src);
|
||||
|
||||
void do_lanczos(unsigned char* dst, unsigned char* src, bool xhi, bool yhi, bool pal, bool lc, size_t psep)
|
||||
{
|
||||
unsigned char* dstN[3];
|
||||
unsigned short* dstW[3];
|
||||
unsigned char* srcN[3];
|
||||
unsigned short* srcW[3];
|
||||
dstN[0] = dst;
|
||||
dstN[1] = dst + psep;
|
||||
dstN[2] = dst + 2 * psep;
|
||||
dstW[0] = reinterpret_cast<unsigned short*>(dst);
|
||||
dstW[1] = reinterpret_cast<unsigned short*>(dst + psep);
|
||||
dstW[2] = reinterpret_cast<unsigned short*>(dst + 2 * psep);
|
||||
srcN[0] = src;
|
||||
srcN[1] = src + 2048;
|
||||
srcN[2] = src + 4096;
|
||||
srcW[0] = reinterpret_cast<unsigned short*>(src);
|
||||
srcW[1] = reinterpret_cast<unsigned short*>(src + 2048);
|
||||
srcW[2] = reinterpret_cast<unsigned short*>(src + 4096);
|
||||
unsigned doffset = pal ? (xhi ? 640 : 320) : (xhi ? 598 : 298);
|
||||
unsigned soffset = xhi ? 512 : 256;
|
||||
void (*fn8)(unsigned char* dst, unsigned char* src);
|
||||
void (*fn16)(unsigned short* dst, unsigned short* src);
|
||||
if(xhi && pal) {
|
||||
fn8 = lanczos_512_640_8;
|
||||
fn16 = lanczos_512_640_16;
|
||||
} else if(xhi && !pal) {
|
||||
fn8 = lanczos_512_598_8;
|
||||
fn16 = lanczos_512_598_16;
|
||||
} else if(!xhi && pal) {
|
||||
fn8 = lanczos_256_320_8;
|
||||
fn16 = lanczos_256_320_16;
|
||||
} else if(!xhi && !pal) {
|
||||
fn8 = lanczos_256_298_8;
|
||||
fn16 = lanczos_256_298_16;
|
||||
}
|
||||
if(lc) {
|
||||
for(unsigned i = 0; i < 3; i++)
|
||||
fn8(dstN[i], srcN[i]);
|
||||
if(yhi)
|
||||
for(unsigned i = 0; i < 3; i++)
|
||||
fn8(dstN[i] + doffset, srcN[i] + soffset);
|
||||
} else {
|
||||
for(unsigned i = 0; i < 3; i++)
|
||||
fn16(dstW[i], srcW[i]);
|
||||
if(yhi)
|
||||
for(unsigned i = 0; i < 3; i++)
|
||||
fn16(dstW[i] + doffset, srcW[i] + soffset);
|
||||
}
|
||||
}
|
||||
|
||||
void call_render_yuv(unsigned char* buffer, unsigned char* buf, size_t psep, int pkt_type, int32_t flags)
|
||||
{
|
||||
render_yuv_t render_yuv = get_renderer_for(flags);
|
||||
unsigned char tmp[6144];
|
||||
if(flags & FLAG_AR_CORRECT) {
|
||||
render_yuv(tmp, buf, 2048, pkt_type & CMD_HIRES, pkt_type & CMD_INTERLACED);
|
||||
bool xhi = (flags & FLAG_WIDTH);
|
||||
bool yhi = (flags & FLAG_HEIGHT);
|
||||
bool pal = (pkt_type & CMD_PAL);
|
||||
bool lc = (flags & FLAG_8BIT);
|
||||
do_lanczos(buffer, tmp, xhi, yhi, pal, lc, psep);
|
||||
} else
|
||||
render_yuv(buffer, buf, psep, pkt_type & CMD_HIRES, pkt_type & CMD_INTERLACED);
|
||||
}
|
||||
|
||||
size_t render_frame(sdmp_input_stream& in, int pkt_type, int32_t flags, unsigned char* buffer)
|
||||
{
|
||||
unsigned char buf[4096];
|
||||
unsigned physline = 0;
|
||||
size_t psep = calculate_plane_separation(flags, pkt_type);
|
||||
size_t lsep = calculate_line_separation(flags, pkt_type);
|
||||
for(unsigned i = 0; i < 256; i++) {
|
||||
in.read_linepair(buf);
|
||||
if(!is_renderable_line(pkt_type, i, physline))
|
||||
continue;
|
||||
call_render_yuv(buffer + physline * lsep, buf, psep, pkt_type, flags);
|
||||
physline++;
|
||||
}
|
||||
if(pkt_type & CMD_PAL) {
|
||||
//Render a black line to pad the image.
|
||||
memset(buf, 0, 4096);
|
||||
call_render_yuv(buffer + physline * lsep, buf, psep, pkt_type, flags);
|
||||
}
|
||||
return 3 * psep;
|
||||
}
|
||||
|
||||
void write_frame(std::ostream& yout, unsigned char* buffer, size_t bufsize, unsigned times_ctr, uint64_t& frames)
|
||||
{
|
||||
for(unsigned k = 0; k < times_ctr; k++)
|
||||
yout.write(reinterpret_cast<char*>(buffer), bufsize);
|
||||
if(!yout)
|
||||
throw std::runtime_error("Can't write frame");
|
||||
frames += times_ctr;
|
||||
}
|
||||
|
||||
void sdump2sox(std::istream& in, std::ostream& yout, std::ostream& sout, std::ostream& tout, int32_t flags)
|
||||
{
|
||||
sdmp_input_stream sdmp_in(in);
|
||||
sox_output sox_out(sout, sdmp_in.get_apurate(), flags & FLAG_OFFSET2);
|
||||
time_tracker ts(sdmp_in.get_cpurate());
|
||||
dup_tracker dupt(tout, flags);
|
||||
|
||||
load_rgb2yuv_matrix(flags);
|
||||
|
||||
if(flags & FLAG_OFFSET2)
|
||||
ts.add_2s();
|
||||
if(flags & FLAG_DEDUP) {
|
||||
tout << "# timecode format v2" << std::endl;
|
||||
if(flags & FLAG_10FRAMES)
|
||||
tout << "0\n200\n400\n600\n800\n1000\n1200\n1400\n1600\n1800" << std::endl;
|
||||
}
|
||||
|
||||
uint64_t frames = 0;
|
||||
bool is_pal = false;
|
||||
|
||||
while(true) {
|
||||
bool lf = false;
|
||||
int pkttype = sdmp_in.read_command();
|
||||
if(pkttype < 0)
|
||||
break; //End of stream.
|
||||
if((pkttype & 0xF0) == 0) {
|
||||
//Picture. Read the 1MiB of picture data one line pair at a time.
|
||||
size_t fsize = render_frame(sdmp_in, pkttype, flags, yuv_buffer);
|
||||
is_pal = is_pal || (pkttype & CMD_PAL);
|
||||
uint32_t times = dupt.process(yuv_buffer, fsize, pkttype, ts);
|
||||
write_frame(yout, yuv_buffer, fsize, times, frames);
|
||||
ts.advance(pkttype & CMD_PAL, pkttype & CMD_INTERLACED);
|
||||
lf = true;
|
||||
} else if(pkttype == 16) {
|
||||
sdmp_in.copy_audio_sample(sox_out);
|
||||
} else {
|
||||
std::ostringstream str;
|
||||
str << "Unknown command byte " << static_cast<unsigned>(pkttype);
|
||||
throw std::runtime_error(str.str());
|
||||
}
|
||||
if(lf && frames % 100 == 0) {
|
||||
std::cout << "\e[1G" << frames << " frames, " << sox_out.get_samples() << " samples."
|
||||
<< std::flush;
|
||||
}
|
||||
}
|
||||
sox_out.close();
|
||||
std::cout << "Sound sampling rate is " << static_cast<double>(sdmp_in.get_apurate()) / 768.0 << "Hz"
|
||||
<< std::endl;
|
||||
std::cout << "Wrote " << sox_out.get_samples() << " samples." << std::endl;
|
||||
std::cout << "Audio length is " << 768.0 * sox_out.get_samples() / sdmp_in.get_apurate() << "s." << std::endl;
|
||||
double vrate = 0;
|
||||
double vrate2 = 0;
|
||||
if(is_pal)
|
||||
vrate2 = 425568.0;
|
||||
else if(flags & FLAG_FRAMERATE)
|
||||
vrate2 = 357368.0;
|
||||
else
|
||||
vrate2 = 357366.0;
|
||||
vrate = sdmp_in.get_cpurate() / vrate2;
|
||||
std::cout << "Video frame rate is " << sdmp_in.get_cpurate() << "/" << vrate2 << "Hz" << std::endl;
|
||||
std::cout << "Wrote " << frames << " frames." << std::endl;
|
||||
std::cout << "Video length is " << frames / vrate << "s." << std::endl;
|
||||
}
|
||||
|
||||
void syntax()
|
||||
{
|
||||
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 (no effect if dedup)." << std::endl;
|
||||
std::cerr << "-l\tOffset timecodes by inserting 10 frames spanning 2 seconds (dedup only)." << std::endl;
|
||||
std::cerr << "-L\tOffset timecodes by 2 seconds (dedup only)." << std::endl;
|
||||
std::cerr << "-A\tDo output AR correction." << 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;
|
||||
std::cerr << "-8\tDump using 8 bits instead of 16 bits." << std::endl;
|
||||
}
|
||||
|
||||
void reached_main();
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
reached_main();
|
||||
if(argc < 4) {
|
||||
syntax();
|
||||
return 1;
|
||||
}
|
||||
uint32_t flags = 0;
|
||||
uint32_t idx1 = 0;
|
||||
uint32_t idx2 = 0;
|
||||
uint32_t idx3 = 0;
|
||||
uint32_t idx4 = 0;
|
||||
for(int i = 1; i < argc; i++) {
|
||||
if(argv[i][0] == '-')
|
||||
for(unsigned j = 1; argv[i][j]; j++)
|
||||
switch(argv[i][j]) {
|
||||
case 'W':
|
||||
flags |= FLAG_WIDTH;
|
||||
break;
|
||||
case 'H':
|
||||
flags |= FLAG_HEIGHT;
|
||||
break;
|
||||
case 'F':
|
||||
flags |= FLAG_FRAMERATE;
|
||||
break;
|
||||
case 'D':
|
||||
flags |= FLAG_DEDUP;
|
||||
break;
|
||||
case 'f':
|
||||
flags |= FLAG_FULLRANGE;
|
||||
break;
|
||||
case 'h':
|
||||
flags |= (FLAG_FAKENLARGE | FLAG_WIDTH | FLAG_HEIGHT);
|
||||
break;
|
||||
case 'l':
|
||||
flags |= (FLAG_10FRAMES | FLAG_OFFSET2);
|
||||
break;
|
||||
case 'L':
|
||||
flags |= FLAG_OFFSET2;
|
||||
break;
|
||||
case 'A':
|
||||
flags |= FLAG_AR_CORRECT;
|
||||
break;
|
||||
case '7':
|
||||
if(flags & FLAG_CS_MASK) {
|
||||
syntax();
|
||||
return 1;
|
||||
}
|
||||
flags |= FLAG_ITU709;
|
||||
break;
|
||||
case '2':
|
||||
if(flags & FLAG_CS_MASK) {
|
||||
syntax();
|
||||
return 1;
|
||||
}
|
||||
flags |= FLAG_SMPTE240M;
|
||||
break;
|
||||
case '8':
|
||||
flags |= FLAG_8BIT;
|
||||
break;
|
||||
default:
|
||||
syntax();
|
||||
return 1;
|
||||
}
|
||||
else if(!idx1)
|
||||
idx1 = i;
|
||||
else if(!idx2)
|
||||
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;
|
||||
return 2;
|
||||
}
|
||||
std::ofstream yout(argv[idx2], std::ios::out | std::ios::binary);
|
||||
if(!yout) {
|
||||
std::cerr << "Error: Can't open '" << argv[idx2] << "'" << std::endl;
|
||||
return 2;
|
||||
}
|
||||
std::ofstream sout(argv[idx3], std::ios::out | std::ios::binary);
|
||||
if(!sout) {
|
||||
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, 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;
|
||||
}
|
|
@ -1,235 +0,0 @@
|
|||
#if defined(BSNES_V084) || defined(BSNES_V085) || defined(BSNES_V086) || defined(BSNES_V087)
|
||||
#include "lsnes.hpp"
|
||||
#include "core/advdumper.hpp"
|
||||
#include "core/dispatch.hpp"
|
||||
#include "core/moviedata.hpp"
|
||||
#include "interface/romtype.hpp"
|
||||
#include "library/serialization.hpp"
|
||||
#include "video/tcp.hpp"
|
||||
|
||||
#include <iomanip>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <sstream>
|
||||
#include <zlib.h>
|
||||
#include <sstream>
|
||||
#include <fstream>
|
||||
#include <stdexcept>
|
||||
|
||||
#define CUTOFF 2100000000
|
||||
#define SDUMP_FLAG_HIRES 1
|
||||
#define SDUMP_FLAG_INTERLACED 2
|
||||
#define SDUMP_FLAG_OVERSCAN 4
|
||||
#define SDUMP_FLAG_PAL 8
|
||||
|
||||
namespace
|
||||
{
|
||||
void deleter_fn(void* f)
|
||||
{
|
||||
delete reinterpret_cast<std::ofstream*>(f);
|
||||
}
|
||||
|
||||
class sdmp_avsnoop : public information_dispatch
|
||||
{
|
||||
public:
|
||||
sdmp_avsnoop(const std::string& prefix, const std::string& mode) throw(std::bad_alloc,
|
||||
std::runtime_error)
|
||||
: information_dispatch("dump-sdmp")
|
||||
{
|
||||
enable_send_sound();
|
||||
oprefix = prefix;
|
||||
sdump_ss = (mode != "ms");
|
||||
ssize = 0;
|
||||
next_seq = 0;
|
||||
dumped_pic = false;
|
||||
if(mode == "tcp") {
|
||||
out = &(socket_address(prefix).connect());
|
||||
deleter = socket_address::deleter();
|
||||
} else {
|
||||
out = NULL;
|
||||
deleter = deleter_fn;
|
||||
}
|
||||
}
|
||||
|
||||
~sdmp_avsnoop() throw()
|
||||
{
|
||||
try {
|
||||
if(out)
|
||||
deleter(out);
|
||||
} catch(...) {
|
||||
}
|
||||
}
|
||||
|
||||
void on_raw_frame(const uint32_t* raw, bool hires, bool interlaced, bool overscan, unsigned region)
|
||||
{
|
||||
unsigned flags = 0;
|
||||
flags |= (hires ? SDUMP_FLAG_HIRES : 0);
|
||||
flags |= (interlaced ? SDUMP_FLAG_INTERLACED : 0);
|
||||
flags |= (overscan ? SDUMP_FLAG_OVERSCAN : 0);
|
||||
flags |= (region == VIDEO_REGION_PAL ? SDUMP_FLAG_PAL : 0);
|
||||
unsigned char tbuffer[2049];
|
||||
if(!out || (ssize > CUTOFF && !sdump_ss)) {
|
||||
std::cerr << "Starting new segment" << std::endl;
|
||||
if(out)
|
||||
deleter(out);
|
||||
std::ostringstream str;
|
||||
if(sdump_ss)
|
||||
str << oprefix;
|
||||
else
|
||||
str << oprefix << "_" << std::setw(4) << std::setfill('0') << (next_seq++)
|
||||
<< ".sdmp";
|
||||
std::string str2 = str.str();
|
||||
out = new std::ofstream(str2.c_str(), std::ios::out | std::ios::binary);
|
||||
if(!*out)
|
||||
throw std::runtime_error("Failed to open '" + str2 + "'");
|
||||
write32ube(tbuffer, 0x53444D50U);
|
||||
auto rates = our_rom->rtype->get_snes_rate();
|
||||
write32ube(tbuffer + 4, rates.first);
|
||||
write32ube(tbuffer + 8, rates.second);
|
||||
out->write(reinterpret_cast<char*>(tbuffer), 12);
|
||||
if(!*out)
|
||||
throw std::runtime_error("Failed to write header to '" + str2 + "'");
|
||||
ssize = 12;
|
||||
}
|
||||
dumped_pic = true;
|
||||
tbuffer[0] = flags;
|
||||
for(unsigned i = 0; i < 512; i++) {
|
||||
for(unsigned j = 0; j < 512; j++)
|
||||
write32ube(tbuffer + (4 * j + 1), raw[512 * i + j]);
|
||||
out->write(reinterpret_cast<char*>(tbuffer + (i ? 1 : 0)), i ? 2048 : 2049);
|
||||
}
|
||||
if(!*out)
|
||||
throw std::runtime_error("Failed to write frame");
|
||||
ssize += 1048577;
|
||||
}
|
||||
|
||||
void on_sample(short l, short r)
|
||||
{
|
||||
if(!out || !dumped_pic)
|
||||
return;
|
||||
unsigned char pkt[5];
|
||||
pkt[0] = 16;
|
||||
write16sbe(pkt + 1, l);
|
||||
write16sbe(pkt + 3, r);
|
||||
out->write(reinterpret_cast<char*>(pkt), 5);
|
||||
if(!*out)
|
||||
throw std::runtime_error("Failed to write sample");
|
||||
ssize += 5;
|
||||
}
|
||||
|
||||
void on_dump_end()
|
||||
{
|
||||
deleter(out);
|
||||
out = NULL;
|
||||
}
|
||||
|
||||
bool get_dumper_flag() throw()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
private:
|
||||
std::string oprefix;
|
||||
bool sdump_ss;
|
||||
bool dumped_pic;
|
||||
uint64_t ssize;
|
||||
uint64_t next_seq;
|
||||
void (*deleter)(void* f);
|
||||
std::ostream* out;
|
||||
};
|
||||
|
||||
sdmp_avsnoop* vid_dumper;
|
||||
|
||||
class adv_sdmp_dumper : public adv_dumper
|
||||
{
|
||||
public:
|
||||
adv_sdmp_dumper() : adv_dumper("INTERNAL-SDMP") { information_dispatch::do_dumper_update(); }
|
||||
~adv_sdmp_dumper() throw();
|
||||
std::set<std::string> list_submodes() throw(std::bad_alloc)
|
||||
{
|
||||
std::set<std::string> x;
|
||||
x.insert("ss");
|
||||
x.insert("ms");
|
||||
x.insert("tcp");
|
||||
return x;
|
||||
}
|
||||
|
||||
unsigned mode_details(const std::string& mode) throw()
|
||||
{
|
||||
if(mode == "ss")
|
||||
return target_type_file;
|
||||
if(mode == "ms")
|
||||
return target_type_prefix;
|
||||
if(mode == "tcp")
|
||||
return target_type_special;
|
||||
return target_type_mask;
|
||||
}
|
||||
|
||||
std::string mode_extension(const std::string& mode) throw()
|
||||
{
|
||||
return "sdmp"; //Ignored anyway in non-ss mode.
|
||||
}
|
||||
|
||||
std::string name() throw(std::bad_alloc)
|
||||
{
|
||||
return "SDMP";
|
||||
}
|
||||
|
||||
std::string modename(const std::string& mode) throw(std::bad_alloc)
|
||||
{
|
||||
if(mode == "ss")
|
||||
return "Single-Segment";
|
||||
if(mode == "ms")
|
||||
return "Multi-Segment";
|
||||
if(mode == "tcp")
|
||||
return "over TCP/IP";
|
||||
return "What?";
|
||||
}
|
||||
|
||||
bool busy()
|
||||
{
|
||||
return (vid_dumper != NULL);
|
||||
}
|
||||
|
||||
void start(const std::string& mode, const std::string& prefix) throw(std::bad_alloc,
|
||||
std::runtime_error)
|
||||
{
|
||||
if(prefix == "")
|
||||
throw std::runtime_error("Expected target");
|
||||
if(vid_dumper)
|
||||
throw std::runtime_error("SDMP Dump already in progress");
|
||||
try {
|
||||
vid_dumper = new sdmp_avsnoop(prefix, mode);
|
||||
} catch(std::bad_alloc& e) {
|
||||
throw;
|
||||
} catch(std::exception& e) {
|
||||
std::ostringstream x;
|
||||
x << "Error starting SDMP dump: " << e.what();
|
||||
throw std::runtime_error(x.str());
|
||||
}
|
||||
messages << "Dumping SDMP (" << mode << ") to " << prefix << std::endl;
|
||||
information_dispatch::do_dumper_update();
|
||||
}
|
||||
|
||||
void end() throw()
|
||||
{
|
||||
if(!vid_dumper)
|
||||
throw std::runtime_error("No SDMP video dump in progress");
|
||||
try {
|
||||
vid_dumper->on_dump_end();
|
||||
messages << "SDMP Dump finished" << std::endl;
|
||||
} catch(std::bad_alloc& e) {
|
||||
throw;
|
||||
} catch(std::exception& e) {
|
||||
messages << "Error ending SDMP dump: " << e.what() << std::endl;
|
||||
}
|
||||
delete vid_dumper;
|
||||
vid_dumper = NULL;
|
||||
information_dispatch::do_dumper_update();
|
||||
}
|
||||
} adv;
|
||||
|
||||
adv_sdmp_dumper::~adv_sdmp_dumper() throw()
|
||||
{
|
||||
}
|
||||
}
|
||||
#endif
|
Loading…
Add table
Reference in a new issue