1 /*******************************************************************************
2 schroedinger_encode.c
3
4 libquicktime - A library for reading and writing quicktime/avi/mp4 files.
5 http://libquicktime.sourceforge.net
6
7 Copyright (C) 2002 Heroine Virtual Ltd.
8 Copyright (C) 2002-2011 Members of the libquicktime project.
9
10 This library is free software; you can redistribute it and/or modify it under
11 the terms of the GNU Lesser General Public License as published by the Free
12 Software Foundation; either version 2.1 of the License, or (at your option)
13 any later version.
14
15 This library is distributed in the hope that it will be useful, but WITHOUT
16 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
18 details.
19
20 You should have received a copy of the GNU Lesser General Public License along
21 with this library; if not, write to the Free Software Foundation, Inc., 51
22 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 *******************************************************************************/
24
25 #define LQT_LIBQUICKTIME /* Hack: This prevents multiple compilation of
26 get_codec_api_version() */
27
28 #include "schroedinger.h"
29 #include <quicktime/colormodels.h>
30 #include <string.h>
31
32 #define LOG_DOMAIN "schroenc"
33
34 static void copy_frame_8(quicktime_t * file,
35 unsigned char **row_pointers,
36 SchroFrame * frame,
37 int track);
38
lqt_schroedinger_set_enc_parameter(quicktime_t * file,int track,const char * key,const void * value)39 int lqt_schroedinger_set_enc_parameter(quicktime_t *file,
40 int track,
41 const char *key,
42 const void *value)
43 {
44 int i, j;
45 double v;
46 int found = 0;
47 quicktime_video_map_t *vtrack = &file->vtracks[track];
48 schroedinger_codec_t *codec = vtrack->codec->priv;
49
50 /* Find the parameter */
51 i = 0;
52
53 while(encode_parameters_schroedinger[i].name)
54 {
55 if(!strcmp(key, encode_parameters_schroedinger[i].name))
56 break;
57 i++;
58 }
59 if(!encode_parameters_schroedinger[i].name)
60 return 0;
61 switch(encode_parameters_schroedinger[i].type)
62 {
63 case LQT_PARAMETER_INT:
64 v = (double)(*(int*)(value));
65 found = 1;
66 break;
67 case LQT_PARAMETER_FLOAT:
68 v = (double)(*(float*)(value));
69 found = 1;
70 break;
71 case LQT_PARAMETER_STRINGLIST:
72 j = 0;
73 while(encode_parameters_schroedinger[i].stringlist_options[j])
74 {
75 if(!strcmp(encode_parameters_schroedinger[i].stringlist_options[j],
76 (char*)value))
77 {
78 v = (double)(j);
79 found = 1;
80 break;
81 }
82 j++;
83 }
84 break;
85 default:
86 break;
87 }
88 if(found)
89 {
90 // fprintf(stderr, "schro_encoder_setting_set_double %s %f\n", key + 4, v);
91 schro_encoder_setting_set_double(codec->enc, key + 4, v);
92 }
93 return 0;
94 }
95
flush_data(quicktime_t * file,int track)96 static int flush_data(quicktime_t *file, int track)
97 {
98 SchroStateEnum state;
99 quicktime_video_map_t *vtrack = &file->vtracks[track];
100 schroedinger_codec_t *codec = vtrack->codec->priv;
101 SchroBuffer *enc_buf;
102 int presentation_frame;
103 int parse_code;
104 int result = 0;
105
106 while(1)
107 {
108 state = schro_encoder_wait(codec->enc);
109
110 switch(state)
111 {
112 case SCHRO_STATE_HAVE_BUFFER:
113 case SCHRO_STATE_END_OF_STREAM:
114 enc_buf = schro_encoder_pull(codec->enc, &presentation_frame);
115 parse_code = enc_buf->data[4];
116
117 // fprintf(stderr, "Parse code: %d, state: %d\n",
118 // parse_code, state);
119
120 /* Append to enc_buffer */
121 if(codec->enc_buffer_alloc < codec->enc_buffer_size + enc_buf->length)
122 {
123 codec->enc_buffer_alloc = codec->enc_buffer_size + enc_buf->length + 1024;
124 codec->enc_buffer = realloc(codec->enc_buffer,
125 codec->enc_buffer_alloc);
126 }
127 memcpy(codec->enc_buffer + codec->enc_buffer_size,
128 enc_buf->data, enc_buf->length);
129 codec->enc_buffer_size += enc_buf->length;
130
131 if(SCHRO_PARSE_CODE_IS_PICTURE(parse_code))
132 {
133 int pic_num, keyframe;
134
135 pic_num = (enc_buf->data[13] << 24) |
136 (enc_buf->data[14] << 16) |
137 (enc_buf->data[15] << 8) |
138 (enc_buf->data[16]);
139
140 if(SCHRO_PARSE_CODE_IS_INTRA(parse_code) &&
141 SCHRO_PARSE_CODE_IS_REFERENCE(parse_code))
142 keyframe = 1;
143 else
144 keyframe = 0;
145
146 /* Write the frame */
147
148 lqt_write_frame_header(file, track,
149 pic_num, -1, keyframe);
150
151 result = !quicktime_write_data(file, codec->enc_buffer,
152 codec->enc_buffer_size);
153
154 lqt_write_frame_footer(file, track);
155
156 codec->enc_buffer_size = 0;
157
158 }
159 else if(SCHRO_PARSE_CODE_IS_END_OF_SEQUENCE(parse_code))
160 {
161
162 if(!codec->enc_eof)
163 {
164 /* Special case: We need to add a final sample to the stream */
165
166 if(vtrack->duration <= vtrack->timestamps[vtrack->current_position-1])
167 {
168 quicktime_trak_t * trak = vtrack->track;
169 quicktime_stts_t * stts = &trak->mdia.minf.stbl.stts;
170 lqt_video_append_timestamp(file, track,
171 vtrack->timestamps[vtrack->current_position-1] +
172 stts->default_duration, 1);
173 }
174 else
175 lqt_video_append_timestamp(file, track, vtrack->duration, 1);
176
177 lqt_write_frame_header(file, track, vtrack->current_position, -1, 0);
178 result = !quicktime_write_data(file, codec->enc_buffer,
179 codec->enc_buffer_size);
180 lqt_write_frame_footer(file, track);
181 vtrack->current_position++;
182 codec->enc_eof = 1;
183 }
184 else
185 lqt_log(file, LQT_LOG_WARNING, LOG_DOMAIN,
186 "Discarding redundant sequence end code");
187
188 codec->enc_buffer_size = 0;
189 }
190
191 schro_buffer_unref (enc_buf);
192 if(state == SCHRO_STATE_END_OF_STREAM)
193 return result;
194 break;
195 case SCHRO_STATE_NEED_FRAME:
196 return result;
197 break;
198 case SCHRO_STATE_AGAIN:
199 break;
200 }
201 }
202 return result;
203 }
204
set_interlacing(quicktime_t * file,int track,SchroVideoFormat * format)205 static void set_interlacing(quicktime_t * file, int track, SchroVideoFormat * format)
206 {
207 quicktime_video_map_t *vtrack = &file->vtracks[track];
208 quicktime_stsd_table_t *stsd;
209
210 stsd = vtrack->track->mdia.minf.stbl.stsd.table;
211
212 if(stsd->has_fiel)
213 return;
214
215 switch(vtrack->interlace_mode)
216 {
217 case LQT_INTERLACE_NONE:
218 lqt_set_fiel(file, track, 1, 0);
219 format->interlaced = 0;
220 format->top_field_first = 0;
221
222 break;
223 case LQT_INTERLACE_TOP_FIRST:
224 lqt_set_fiel(file, track, 2, 9);
225 #if 0 /* Don't encode field pictures */
226 schro_encoder_setting_set_double(codec->enc,
227 "interlaced_coding", 1);
228 #endif
229 format->interlaced = 1;
230 format->top_field_first = 1;
231 break;
232 case LQT_INTERLACE_BOTTOM_FIRST:
233 lqt_set_fiel(file, track, 2, 14);
234 #if 0 /* Don't encode field pictures */
235 schro_encoder_setting_set_double(codec->enc,
236 "interlaced_coding", 1);
237 #endif
238 format->interlaced = 1;
239 format->top_field_first = 0;
240 break;
241 }
242 }
243
lqt_schroedinger_encode_video(quicktime_t * file,unsigned char ** row_pointers,int track)244 int lqt_schroedinger_encode_video(quicktime_t *file,
245 unsigned char **row_pointers,
246 int track)
247 {
248 SchroFrame * frame;
249 SchroVideoFormat * format;
250 quicktime_video_map_t *vtrack = &file->vtracks[track];
251 schroedinger_codec_t *codec = vtrack->codec->priv;
252
253 if(!row_pointers)
254 {
255 vtrack->stream_cmodel = BC_YUV420P;
256 return 0;
257 }
258
259 if(!codec->enc_copy_frame)
260 {
261 int pixel_width, pixel_height;
262 /* Initialize */
263 codec->enc_copy_frame = copy_frame_8;
264
265 format = schro_encoder_get_video_format(codec->enc);
266
267 format->width = quicktime_video_width(file, track);
268 format->height = quicktime_video_height(file, track);
269
270 format->clean_width = format->width;
271 format->clean_height = format->height;
272 format->left_offset = 0;
273 format->top_offset = 0;
274
275 format->frame_rate_numerator = lqt_video_time_scale(file, track);
276 format->frame_rate_denominator = lqt_frame_duration(file, track, NULL);
277
278 lqt_get_pixel_aspect(file, track, &pixel_width, &pixel_height);
279
280 format->aspect_ratio_numerator = pixel_width;
281 format->aspect_ratio_denominator = pixel_height;
282
283 set_interlacing(file, track, format);
284
285 schro_video_format_set_std_signal_range(format,
286 lqt_schrodinger_get_signal_range(vtrack->stream_cmodel));
287
288 format->chroma_format =
289 lqt_schrodinger_get_chroma_format(vtrack->stream_cmodel);
290
291 codec->frame_format = lqt_schrodinger_get_frame_format(format);
292
293 schro_encoder_set_video_format(codec->enc, format);
294
295 free(format);
296
297 // schro_debug_set_level(4);
298
299 schro_encoder_start(codec->enc);
300 }
301
302 frame = schro_frame_new_and_alloc(NULL,
303 codec->frame_format,
304 quicktime_video_width(file, track),
305 quicktime_video_height(file, track));
306
307 codec->enc_copy_frame(file, row_pointers, frame, track);
308
309 schro_encoder_push_frame(codec->enc, frame);
310
311 flush_data(file, track);
312
313 return 0;
314 }
315
lqt_schroedinger_flush(quicktime_t * file,int track)316 int lqt_schroedinger_flush(quicktime_t *file,
317 int track)
318 {
319 quicktime_video_map_t *vtrack = &file->vtracks[track];
320 schroedinger_codec_t *codec = vtrack->codec->priv;
321 schro_encoder_end_of_stream(codec->enc);
322 flush_data(file, track);
323 return 0;
324 }
325
copy_frame_8(quicktime_t * file,unsigned char ** row_pointers,SchroFrame * frame,int track)326 static void copy_frame_8(quicktime_t * file,
327 unsigned char **row_pointers,
328 SchroFrame * frame,
329 int track)
330 {
331 uint8_t * cpy_rows[3];
332 quicktime_video_map_t *vtrack = &file->vtracks[track];
333
334 cpy_rows[0] = frame->components[0].data;
335 cpy_rows[1] = frame->components[1].data;
336 cpy_rows[2] = frame->components[2].data;
337
338 lqt_rows_copy(cpy_rows, row_pointers,
339 quicktime_video_width(file, track),
340 quicktime_video_height(file, track),
341 vtrack->stream_row_span, vtrack->stream_row_span_uv,
342 frame->components[0].stride,
343 frame->components[1].stride,
344 vtrack->stream_cmodel);
345 }
346