1 /*
2 * KCemu -- The emulator for the KC85 homecomputer series and much more.
3 * Copyright (C) 1997-2010 Torsten Paul
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include "kc/config.h"
21 #ifdef HAVE_LIBSCHROEDINGER
22
23 #include <string.h>
24
25 #include "kc/system.h"
26
27 #include "ui/gtk/schro.h"
28
29 void
image_free(SchroFrame * frame,void * priv)30 SchroedingerVideoEncoder::image_free(SchroFrame *frame, void *priv)
31 {
32 delete[] (byte_t *)priv;
33 }
34
SchroedingerVideoEncoder(void)35 SchroedingerVideoEncoder::SchroedingerVideoEncoder(void)
36 {
37 _f = NULL;
38 _buf = NULL;
39 _image = NULL;
40 }
41
~SchroedingerVideoEncoder(void)42 SchroedingerVideoEncoder::~SchroedingerVideoEncoder(void)
43 {
44 close();
45 }
46
47 bool
init(const char * filename,int width,int height,int fps_den,double quality)48 SchroedingerVideoEncoder::init(const char *filename, int width, int height, int fps_den, double quality)
49 {
50 if (filename == NULL)
51 return false;
52
53 if (quality < 0)
54 quality = 0;
55 if (quality > 1)
56 quality = 1;
57
58 _f = fopen(filename, "wb+");
59 if (_f == NULL)
60 return false;
61
62 _width = width;
63 _height = height;
64
65 schro_init();
66
67 _encoder = schro_encoder_new();
68 SchroVideoFormat *format = schro_encoder_get_video_format(_encoder);
69 format->width = width;
70 format->height = height;
71 format->clean_width = width;
72 format->clean_height = height;
73 format->top_offset = 0;
74 format->left_offset = 0;
75 format->aspect_ratio_numerator = 1;
76 format->aspect_ratio_denominator = 1;
77 format->frame_rate_numerator = 50;
78 format->frame_rate_denominator = fps_den;
79 format->chroma_format = SCHRO_CHROMA_444;
80 format->interlaced = FALSE;
81 schro_encoder_set_video_format(_encoder, format);
82 free(format);
83
84 schro_encoder_setting_set_double(_encoder, "quality", 10 * quality);
85 schro_encoder_start(_encoder);
86
87 return true;
88 }
89
90 void
allocate_color_rgb(int idx,int r,int g,int b)91 SchroedingerVideoEncoder::allocate_color_rgb(int idx, int r, int g, int b)
92 {
93 _col[idx].y = (0.257 * r) + (0.504 * g) + (0.098 * b) + 16;
94 _col[idx].u = -(0.148 * r) - (0.291 * g) + (0.439 * b) + 128;
95 _col[idx].v = (0.439 * r) - (0.368 * g) - (0.071 * b) + 128;
96 }
97
98 bool
encode_loop()99 SchroedingerVideoEncoder::encode_loop()
100 {
101 while (242)
102 {
103 switch (schro_encoder_wait(_encoder))
104 {
105 case SCHRO_STATE_AGAIN:
106 break;
107 case SCHRO_STATE_NEED_FRAME:
108 case SCHRO_STATE_END_OF_STREAM:
109 return true;
110 case SCHRO_STATE_HAVE_BUFFER:
111 {
112 SchroBuffer *buffer = schro_encoder_pull(_encoder, NULL);
113 if (fwrite(buffer->data, buffer->length, 1, _f) != 1)
114 return false;
115
116 schro_buffer_unref(buffer);
117 return true;
118 }
119 default:
120 return false;
121 }
122 }
123 }
124
125 bool
encode(byte_t * image,byte_t * dirty)126 SchroedingerVideoEncoder::encode(byte_t *image, byte_t *dirty)
127 {
128 int count = _width * _height;
129 byte_t *buf = new byte_t[4 * count];
130
131 for (int src = 0, dst = 0;src < count;src++, dst += 4)
132 {
133 color_t *col = &_col[image[src]];
134 buf[dst] = 0;
135 buf[dst + 1] = col->y;
136 buf[dst + 2] = col->u;
137 buf[dst + 3] = col->v;
138 }
139
140 if (!encode_loop())
141 return false;
142
143 SchroFrame *frame = schro_frame_new_from_data_AYUV(buf, _width, _height);
144 schro_frame_set_free_callback(frame, image_free, buf);
145 schro_encoder_push_frame(_encoder, frame);
146
147 return encode_loop();
148 }
149
150 void
close(void)151 SchroedingerVideoEncoder::close(void)
152 {
153 if (_f != NULL)
154 {
155 schro_encoder_end_of_stream(_encoder);
156 encode_loop();
157 schro_encoder_free(_encoder);
158 fclose(_f);
159 }
160
161 if (_buf != NULL)
162 delete _buf;
163
164 if (_image != NULL)
165 delete _image;
166
167 _f = NULL;
168 _buf = NULL;
169 _image = NULL;
170 }
171
172 #endif /* HAVE_LIBSCHROEDINGER */
173