Actually call on_reset callback
[lsnes.git] / src / video / avi / codec / video / cscd.cpp
blob1c3918f2fb609ac880f0cb4105d65b51846c64f1
1 #include "video/avi/codec.hpp"
2 #include "core/instance.hpp"
3 #include "core/settings.hpp"
4 #include "library/zlibstream.hpp"
5 #include <limits>
6 #include <cstring>
7 #include <cerrno>
8 #include <stdexcept>
10 #define CBUFFER 16384
12 namespace
14 settingvar::supervariable<settingvar::model_int<0,9>> clvl(lsnes_setgrp, "avi-cscd-compression",
15 "AVI‣CSCD‣Compression", 7);
16 settingvar::supervariable<settingvar::model_int<0,999999999>> kint(lsnes_setgrp, "avi-cscd-keyint",
17 "AVI‣CSCD‣Keyframe interval", 0);
19 struct avi_codec_cscd : public avi_video_codec
21 avi_codec_cscd(uint32_t _level, uint32_t maxpframes);
22 ~avi_codec_cscd();
23 avi_video_codec::format reset(uint32_t width, uint32_t height, uint32_t fps_n, uint32_t fps_d);
24 void frame(uint32_t* data, uint32_t stride);
25 bool ready();
26 avi_packet getpacket();
27 private:
28 void readrow(uint32_t* rptr);
29 avi_packet out;
30 bool ready_flag;
31 unsigned iwidth;
32 unsigned iheight;
33 unsigned ewidth;
34 unsigned eheight;
35 unsigned pframes;
36 unsigned max_pframes;
37 unsigned level;
38 zlibstream z;
39 std::vector<uint8_t> row;
40 std::vector<uint8_t> prevframe;
43 avi_codec_cscd::~avi_codec_cscd()
47 unsigned getzlevel(uint32_t _level)
49 if(_level < 0 || _level > 9)
50 throw std::runtime_error("Invalid compression level");
51 return _level;
54 avi_codec_cscd::avi_codec_cscd(uint32_t _level, uint32_t maxpframes)
55 : z(getzlevel(_level))
57 level = _level;
58 max_pframes = maxpframes;
61 avi_video_codec::format avi_codec_cscd::reset(uint32_t width, uint32_t height, uint32_t fps_n, uint32_t fps_d)
63 pframes = std::numeric_limits<unsigned>::max(); //Next frame has to be keyframe.
64 iwidth = width;
65 iheight = height;
66 ewidth = (iwidth + 3) >> 2 << 2;
67 eheight = (iheight + 3) >> 2 << 2;
68 ready_flag = true;
69 row.resize(3 * ewidth);
70 prevframe.resize(3 * ewidth * eheight);
71 memset(&row[0], 0, 3 * ewidth);
72 memset(&prevframe[0], 0, 3 * ewidth * eheight);
73 avi_video_codec::format fmt(ewidth, eheight, 0x44435343, 24);
74 return fmt;
77 void avi_codec_cscd::frame(uint32_t* data, uint32_t stride)
79 bool keyframe = false;
80 if(pframes >= max_pframes) {
81 keyframe = true;
82 pframes = 0;
83 } else
84 pframes++;
86 unsigned char h[2];
87 h[0] = (keyframe ? 0x3 : 0x2) | (level << 4);
88 h[1] = 8; //RGB24.
89 z.reset(h, 2);
91 for(uint32_t y = 0; y < eheight; y++) {
92 if(y < eheight - iheight)
93 readrow(NULL);
94 else
95 readrow(data + (eheight - y - 1) * stride);
96 if(keyframe) {
97 memcpy(&prevframe[3 * y * ewidth], &row[0], 3 * ewidth);
98 } else {
99 //Ew, we need to have prevframe = row, row = row - prevframe at the same time.
100 for(unsigned i = 0; i < 3 * ewidth; i++) {
101 uint8_t tmp = row[i];
102 row[i] -= prevframe[3 * y * ewidth + i];
103 prevframe[3 * y * ewidth + i] = tmp;
106 z.write(&row[0], row.size());
108 z.read(out.payload);
109 out.typecode = 0x6264; //Not exactly correct according to specs...
110 out.hidden = false;
111 out.indexflags = keyframe ? 0x10 : 0;
112 ready_flag = false;
115 bool avi_codec_cscd::ready()
117 return ready_flag;
120 avi_packet avi_codec_cscd::getpacket()
122 ready_flag = true;
123 return out;
126 void avi_codec_cscd::readrow(uint32_t* rptr)
128 if(!rptr)
129 memset(&row[0], 0, 3 * iwidth);
130 else
131 for(uint32_t i = 0; i < iwidth; i++) {
132 row[3 * i + 0] = rptr[i] >> 16;
133 row[3 * i + 1] = rptr[i] >> 8;
134 row[3 * i + 2] = rptr[i] >> 0;
138 avi_video_codec_type rgb("cscd", "Camstudio video codec",
139 []() -> avi_video_codec* {
140 return new avi_codec_cscd(clvl(*CORE().settings), kint(*CORE().settings));