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