1 /*******************************************************************************
2 dv.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 #include "lqt_private.h"
26 #include <quicktime/colormodels.h>
27 #include <libdv/dv.h>
28 #include <pthread.h>
29 #include <string.h>
30
31 #include "dv.h"
32
33 // Buffer sizes
34 #define DV_NTSC_SIZE 120000
35 #define DV_PAL_SIZE 144000
36
37 typedef struct
38 {
39 dv_decoder_t *dv_decoder;
40 dv_encoder_t *dv_encoder;
41 unsigned char *data;
42 unsigned char *temp_frame, **temp_rows;
43
44 /* Parameters */
45 int decode_quality;
46 int anamorphic16x9;
47 int vlc_encode_passes;
48 int clamp_luma, clamp_chroma;
49
50 int add_ntsc_setup;
51
52 int rem_ntsc_setup;
53
54 int parameters_changed;
55 } quicktime_dv_codec_t;
56
57 static pthread_mutex_t libdv_init_mutex = PTHREAD_MUTEX_INITIALIZER;
58
delete_codec(quicktime_codec_t * codec_base)59 static int delete_codec(quicktime_codec_t *codec_base)
60 {
61 quicktime_dv_codec_t *codec = codec_base->priv;
62
63 if(codec->dv_decoder)
64 {
65 dv_decoder_free( codec->dv_decoder );
66 codec->dv_decoder = NULL;
67 }
68
69 if(codec->dv_encoder)
70 {
71 dv_encoder_free( codec->dv_encoder );
72 codec->dv_encoder = NULL;
73 }
74
75 if(codec->temp_frame) free(codec->temp_frame);
76 if(codec->temp_rows) free(codec->temp_rows);
77 free(codec->data);
78 free(codec);
79 return 0;
80 }
81
check_sequentiality(unsigned char ** row_pointers,int bytes_per_row,int height)82 static int check_sequentiality( unsigned char **row_pointers,
83 int bytes_per_row,
84 int height )
85 {
86 int i = 0;
87
88 for(; i < height-1; i++)
89 {
90 if( row_pointers[i+1] - row_pointers[i] != bytes_per_row )
91 {
92 return 0;
93 }
94 }
95 return 1;
96 }
97
encode(quicktime_t * file,unsigned char ** row_pointers,int track)98 static int encode(quicktime_t *file, unsigned char **row_pointers, int track)
99 {
100 quicktime_video_map_t *vtrack = &file->vtracks[track];
101 quicktime_dv_codec_t *codec = vtrack->codec->priv;
102 quicktime_trak_t *trak = vtrack->track;
103 int width = trak->tkhd.track_width;
104 int height = trak->tkhd.track_height;
105 int width_i = 720;
106 int height_i = (height <= 480) ? 480 : 576;
107 int i;
108 unsigned char **input_rows;
109 int isPAL = (height_i == 480) ? 0 : 1;
110 int data_length = isPAL ? DV_PAL_SIZE : DV_NTSC_SIZE;
111 int result = 0;
112 dv_color_space_t encode_dv_colormodel = 0;
113
114 if(!row_pointers)
115 {
116 vtrack->stream_cmodel = BC_YUV422;
117 vtrack->interlace_mode = LQT_INTERLACE_BOTTOM_FIRST;
118 return 0;
119 }
120
121
122 if( codec->dv_encoder != NULL && codec->parameters_changed )
123 {
124 dv_encoder_free( codec->dv_encoder );
125 codec->dv_encoder = NULL;
126 codec->parameters_changed = 0;
127 }
128
129 if( ! codec->dv_encoder )
130 {
131 pthread_mutex_lock( &libdv_init_mutex );
132
133
134 codec->dv_encoder = dv_encoder_new( codec->rem_ntsc_setup,
135 codec->clamp_luma,
136 codec->clamp_chroma );
137
138 codec->parameters_changed = 0;
139 pthread_mutex_unlock( &libdv_init_mutex );
140 }
141
142 if(codec->dv_encoder)
143 {
144 int is_sequential =
145 check_sequentiality( row_pointers,
146 width_i * cmodel_calculate_pixelsize(BC_YUV422),
147 height );
148
149 encode_dv_colormodel = e_dv_color_yuv;
150 if( width == width_i &&
151 height == height_i &&
152 is_sequential )
153 {
154 input_rows = row_pointers;
155 }
156 else
157 {
158 if(!codec->temp_frame)
159 {
160 codec->temp_frame = malloc(720 * 576 * 2);
161 codec->temp_rows = malloc(sizeof(unsigned char*) * 576);
162 for(i = 0; i < 576; i++)
163 codec->temp_rows[i] = codec->temp_frame + 720 * 2 * i;
164 }
165
166 for(i = 0; i < MIN(height, height_i); i++)
167 {
168 memcpy(codec->temp_rows[i], row_pointers[i], MIN(width, width_i));
169 }
170
171
172 input_rows = codec->temp_rows;
173 }
174
175 // Setup the encoder
176 codec->dv_encoder->is16x9 = codec->anamorphic16x9;
177 codec->dv_encoder->vlc_encode_passes = codec->vlc_encode_passes;
178 codec->dv_encoder->static_qno = 0;
179 codec->dv_encoder->force_dct = DV_DCT_AUTO;
180 codec->dv_encoder->isPAL = isPAL;
181
182
183 dv_encode_full_frame( codec->dv_encoder,
184 input_rows, encode_dv_colormodel, codec->data );
185
186 lqt_write_frame_header(file, track, vtrack->current_position,
187 -1, 0);
188
189 result = !quicktime_write_data(file, codec->data, data_length);
190
191 lqt_write_frame_footer(file, track);
192 }
193
194 return result;
195 }
196
197 // Logic: DV contains a mixture of 420 and 411 so can only
198 // output/input 444 or 422 and libdv can output/input RGB as well so
199 // we include that.
200
201 // This function is used as both reads_colormodel and writes_colormodel
202
set_parameter(quicktime_t * file,int track,const char * key,const void * value)203 static int set_parameter(quicktime_t *file,
204 int track,
205 const char *key,
206 const void *value)
207 {
208 quicktime_dv_codec_t *codec = file->vtracks[track].codec->priv;
209
210 if(!strcasecmp(key, "dv_decode_quality"))
211 {
212 codec->decode_quality = *(int*)value;
213 }
214 else if(!strcasecmp(key, "dv_anamorphic16x9"))
215 {
216 codec->anamorphic16x9 = *(int*)value;
217 }
218 else if(!strcasecmp(key, "dv_vlc_encode_passes"))
219 {
220 codec->vlc_encode_passes = *(int*)value;
221 }
222 else if(!strcasecmp(key, "dv_clamp_luma"))
223 {
224 codec->clamp_luma = *(int*)value;
225 }
226 else if(!strcasecmp(key, "dv_clamp_chroma"))
227 {
228 codec->clamp_chroma = *(int*)value;
229 }
230 else if(!strcasecmp(key, "dv_add_ntsc_setup"))
231 {
232 codec->add_ntsc_setup = *(int*)value;
233 }
234 else if(!strcasecmp(key, "dv_rem_ntsc_setup"))
235 {
236 codec->rem_ntsc_setup = *(int*)value;
237 }
238 else
239 {
240 return 0;
241 }
242
243 codec->parameters_changed = 1;
244 return 0;
245 }
246
quicktime_init_codec_dv(quicktime_codec_t * codec_base,quicktime_audio_map_t * atrack,quicktime_video_map_t * vtrack)247 void quicktime_init_codec_dv(quicktime_codec_t * codec_base,
248 quicktime_audio_map_t *atrack,
249 quicktime_video_map_t *vtrack)
250 {
251 quicktime_dv_codec_t *codec;
252
253 /* Init public items */
254 codec = calloc(1, sizeof(*codec));
255 codec_base->priv = codec;
256
257 codec_base->delete_codec = delete_codec;
258 codec_base->encode_video = encode;
259 codec_base->set_parameter = set_parameter;
260 /* Init private items */
261
262 codec->decode_quality = DV_QUALITY_BEST;
263 codec->vlc_encode_passes = 3;
264
265 codec->data = calloc(1, 144000);
266 }
267