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