r105: This commit was manufactured by cvs2svn to create tag
[cinelerra_cv/mob.git] / hvirtual / quicktime / div3.c
blob279a52b8af555f6b2729e04313bcb79a2c33432b
1 #include "avcodec.h"
2 #include "colormodels.h"
3 #include "funcprotos.h"
4 #include "quicktime.h"
7 #include <pthread.h>
11 typedef struct
13 int decode_initialized;
14 int encode_initialized;
15 AVCodec *decoder;
16 AVCodecContext *decoder_context;
17 AVCodecContext *encoder_context;
18 AVFrame picture;
19 char *temp_frame;
20 char *work_buffer;
21 int buffer_size;
22 int last_frame;
23 int got_key;
24 // ID out of avcodec.h for the codec used
25 int derivative;
28 int bitrate;
29 int bitrate_tolerance;
30 int interlaced;
31 int gop_size;
32 int quantizer;
33 int fix_bitrate;
36 AVCodec *encoder;
37 } quicktime_div3_codec_t;
39 static pthread_mutex_t encode_mutex;
40 static pthread_mutex_t decode_mutex;
41 static int mutex_initialized = 0;
42 static int global_initialized = 0;
45 static int reads_colormodel(quicktime_t *file,
46 int colormodel,
47 int track)
49 return (colormodel == BC_YUV420P);
52 static int writes_colormodel(quicktime_t *file,
53 int colormodel,
54 int track)
56 return (colormodel == BC_RGB888 ||
57 colormodel == BC_RGBA8888 ||
58 colormodel == BC_RGB161616 ||
59 colormodel == BC_RGBA16161616 ||
60 colormodel == BC_YUV888 ||
61 colormodel == BC_YUVA8888 ||
62 colormodel == BC_YUV161616 ||
63 colormodel == BC_YUVA16161616 ||
64 colormodel == BC_YUV420P ||
65 colormodel == BC_YUV422 ||
66 colormodel == BC_COMPRESSED);
71 static void init_mutex()
73 if(!mutex_initialized)
75 pthread_mutexattr_t attr;
76 mutex_initialized = 1;
77 pthread_mutexattr_init(&attr);
78 pthread_mutex_init(&decode_mutex, &attr);
79 pthread_mutex_init(&encode_mutex, &attr);
83 static int delete_codec(quicktime_video_map_t *vtrack)
85 quicktime_div3_codec_t *codec = ((quicktime_codec_t*)vtrack->codec)->priv;
86 if(codec->decode_initialized)
88 pthread_mutex_lock(&decode_mutex);
89 avcodec_close(codec->decoder_context);
90 free(codec->decoder_context);
91 pthread_mutex_unlock(&decode_mutex);
93 if(codec->encode_initialized)
95 pthread_mutex_lock(&encode_mutex);
96 avcodec_close(codec->encoder_context);
97 free(codec->encoder_context);
98 pthread_mutex_unlock(&encode_mutex);
100 if(codec->temp_frame) free(codec->temp_frame);
101 if(codec->work_buffer) free(codec->work_buffer);
102 free(codec);
105 static int init_codec(quicktime_div3_codec_t *codec, int width_i, int height_i)
107 if(!global_initialized)
109 global_initialized = 1;
110 avcodec_init();
111 avcodec_register_all();
115 codec->decoder = avcodec_find_decoder(codec->derivative);
116 if(!codec->decoder)
118 printf("init_codec: avcodec_find_decoder returned NULL.\n");
119 return 1;
122 codec->decoder_context = avcodec_alloc_context();
123 codec->decoder_context->width = width_i;
124 codec->decoder_context->height = height_i;
125 if(avcodec_open(codec->decoder_context, codec->decoder) < 0)
127 printf("init_codec: avcodec_open failed.\n");
129 return 0;
136 int quicktime_div3_is_key(unsigned char *data, long size)
138 int result = 0;
140 // First 2 bits are pict type.
141 result = (data[0] & 0xc0) == 0;
144 return result;
148 static int decode_wrapper(quicktime_div3_codec_t *codec,
149 unsigned char *data,
150 long size)
152 int got_picture = 0;
153 int result;
155 if(!codec->got_key && !quicktime_div3_is_key(data, size)) return 0;
157 if(quicktime_div3_is_key(data, size)) codec->got_key = 1;
159 result = avcodec_decode_video(codec->decoder_context,
160 &codec->picture,
161 &got_picture,
162 codec->work_buffer,
163 size);
164 #ifdef ARCH_X86
165 asm("emms");
166 #endif
167 return result;
172 static int decode(quicktime_t *file, unsigned char **row_pointers, int track)
174 //printf(__FUNCTION__ " div3 1\n");
175 quicktime_video_map_t *vtrack = &(file->vtracks[track]);
176 quicktime_div3_codec_t *codec = ((quicktime_codec_t*)vtrack->codec)->priv;
177 quicktime_trak_t *trak = vtrack->track;
178 int result = 0;
179 int width = trak->tkhd.track_width;
180 int height = trak->tkhd.track_height;
181 int width_i = (int)((float)width / 16 + 0.5) * 16;
182 int height_i = (int)((float)height / 16 + 0.5) * 16;
183 int input_cmodel;
184 int bytes;
185 int i;
186 unsigned char **input_rows;
188 init_mutex();
189 pthread_mutex_lock(&decode_mutex);
192 if(!codec->decode_initialized)
194 init_codec(codec, width_i, height_i);
196 codec->decode_initialized = 1;
199 // Handle seeking
200 if(quicktime_has_keyframes(file, track) &&
201 vtrack->current_position != codec->last_frame + 1)
203 int frame1, frame2 = vtrack->current_position;
205 frame1 = quicktime_get_keyframe_before(file,
206 vtrack->current_position,
207 track);
209 if(frame1 < codec->last_frame &&
210 frame2 > codec->last_frame) frame1 = codec->last_frame + 1;
212 while(frame1 < frame2)
215 quicktime_set_video_position(file, frame1, track);
217 bytes = quicktime_frame_size(file, frame1, track);
219 if(!codec->work_buffer || codec->buffer_size < bytes)
221 if(codec->work_buffer) free(codec->work_buffer);
222 codec->buffer_size = bytes;
223 codec->work_buffer = calloc(1, codec->buffer_size + 100);
227 result = !quicktime_read_data(file,
228 codec->work_buffer,
229 bytes);
232 if(!result)
233 result = decode_wrapper(codec,
234 codec->work_buffer,
235 bytes);
237 frame1++;
240 vtrack->current_position = frame2;
243 codec->last_frame = vtrack->current_position;
244 bytes = quicktime_frame_size(file, vtrack->current_position, track);
245 quicktime_set_video_position(file, vtrack->current_position, track);
247 if(!codec->work_buffer || codec->buffer_size < bytes)
249 if(codec->work_buffer) free(codec->work_buffer);
250 codec->buffer_size = bytes;
251 codec->work_buffer = calloc(1, codec->buffer_size + 100);
253 result = !quicktime_read_data(file, codec->work_buffer, bytes);
255 if(!result)
256 result = decode_wrapper(codec,
257 codec->work_buffer,
258 bytes);
260 pthread_mutex_unlock(&decode_mutex);
272 result = (result <= 0);
273 switch(codec->decoder_context->pix_fmt)
275 case PIX_FMT_YUV420P:
276 input_cmodel = BC_YUV420P;
277 break;
278 case PIX_FMT_YUV422:
279 input_cmodel = BC_YUV422;
280 break;
281 case PIX_FMT_YUV422P:
282 input_cmodel = BC_YUV422P;
283 break;
287 if(!result)
289 int y_out_size = codec->decoder_context->width *
290 codec->decoder_context->height;
291 int u_out_size = codec->decoder_context->width *
292 codec->decoder_context->height /
294 int v_out_size = codec->decoder_context->width *
295 codec->decoder_context->height /
297 int y_in_size = codec->picture.linesize[0] *
298 codec->decoder_context->height;
299 int u_in_size = codec->picture.linesize[1] *
300 codec->decoder_context->height /
302 int v_in_size = codec->picture.linesize[2] *
303 codec->decoder_context->height /
305 input_rows =
306 malloc(sizeof(unsigned char*) *
307 codec->decoder_context->height);
309 for(i = 0; i < codec->decoder_context->height; i++)
310 input_rows[i] = codec->picture.data[0] +
311 i *
312 codec->decoder_context->width *
313 cmodel_calculate_pixelsize(input_cmodel);
315 if(!codec->temp_frame)
317 codec->temp_frame = malloc(y_out_size +
318 u_out_size +
319 v_out_size);
322 if(codec->picture.data[0])
324 for(i = 0; i < codec->decoder_context->height; i++)
326 memcpy(codec->temp_frame + i * codec->decoder_context->width,
327 codec->picture.data[0] + i * codec->picture.linesize[0],
328 codec->decoder_context->width);
331 for(i = 0; i < codec->decoder_context->height; i += 2)
333 memcpy(codec->temp_frame +
334 y_out_size +
335 i / 2 *
336 codec->decoder_context->width / 2,
337 codec->picture.data[1] +
338 i / 2 *
339 codec->picture.linesize[1],
340 codec->decoder_context->width / 2);
342 memcpy(codec->temp_frame +
343 y_out_size +
344 u_out_size +
345 i / 2 *
346 codec->decoder_context->width / 2,
347 codec->picture.data[2] +
348 i / 2 *
349 codec->picture.linesize[2],
350 codec->decoder_context->width / 2);
354 cmodel_transfer(row_pointers, /* Leave NULL if non existent */
355 input_rows,
356 row_pointers[0], /* Leave NULL if non existent */
357 row_pointers[1],
358 row_pointers[2],
359 codec->temp_frame, /* Leave NULL if non existent */
360 codec->temp_frame + y_out_size,
361 codec->temp_frame + y_out_size + u_out_size,
362 file->in_x, /* Dimensions to capture from input frame */
363 file->in_y,
364 file->in_w,
365 file->in_h,
366 0, /* Dimensions to project on output frame */
368 file->out_w,
369 file->out_h,
370 input_cmodel,
371 file->color_model,
372 0, /* When transfering BC_RGBA8888 to non-alpha this is the background color in 0xRRGGBB hex */
373 codec->decoder_context->width, /* For planar use the luma rowspan */
374 width);
376 free(input_rows);
380 return result;
383 static int encode(quicktime_t *file, unsigned char **row_pointers, int track)
385 //printf(__FUNCTION__ " 1\n");
386 quicktime_video_map_t *vtrack = &(file->vtracks[track]);
387 quicktime_div3_codec_t *codec = ((quicktime_codec_t*)vtrack->codec)->priv;
388 quicktime_trak_t *trak = vtrack->track;
389 int width = trak->tkhd.track_width;
390 int height = trak->tkhd.track_height;
391 int result = 0;
392 int width_i = (int)((float)width / 16 + 0.5) * 16;
393 int height_i = (int)((float)height / 16 + 0.5) * 16;
394 AVFrame pict_tmp;
395 int bytes;
396 quicktime_atom_t chunk_atom;
397 //printf(__FUNCTION__ " 1\n");
399 init_mutex();
400 //printf(__FUNCTION__ " 1\n");
402 pthread_mutex_lock(&encode_mutex);
403 if(!codec->encode_initialized)
405 static char *video_rc_eq="tex^qComp";
406 codec->encode_initialized = 1;
407 if(!global_initialized)
409 global_initialized = 1;
410 avcodec_init();
411 avcodec_register_all();
414 codec->encoder = avcodec_find_encoder(codec->derivative);
415 if(!codec->encoder)
417 printf("encode: avcodec_find_encoder returned NULL.\n");
418 pthread_mutex_unlock(&encode_mutex);
419 return 1;
422 codec->encoder_context = avcodec_alloc_context();
423 codec->encoder_context->frame_rate = FRAME_RATE_BASE *
424 quicktime_frame_rate(file, track);
425 codec->encoder_context->width = width_i;
426 codec->encoder_context->height = height_i;
427 codec->encoder_context->gop_size = codec->gop_size;
428 codec->encoder_context->pix_fmt = PIX_FMT_YUV420P;
429 codec->encoder_context->bit_rate = codec->bitrate;
430 codec->encoder_context->bit_rate_tolerance = codec->bitrate_tolerance;
431 codec->encoder_context->rc_eq = video_rc_eq;
432 codec->encoder_context->qmin = 2;
433 codec->encoder_context->qmax = 31;
434 codec->encoder_context->max_qdiff = 3;
435 codec->encoder_context->qblur = 0.5;
436 codec->encoder_context->qcompress = 0.5;
437 codec->encoder_context->me_method = ME_FULL;
439 if(!codec->fix_bitrate)
441 codec->encoder_context->flags |= CODEC_FLAG_QSCALE;
444 if(codec->interlaced)
446 codec->encoder_context->flags |= CODEC_FLAG_INTERLACED_DCT;
450 avcodec_open(codec->encoder_context, codec->encoder);
452 codec->work_buffer = calloc(1, width_i * height_i * 3);
453 codec->buffer_size = width_i * height_i * 3;
455 //printf(__FUNCTION__ " 1\n");
459 if(width_i == width &&
460 height_i == height &&
461 file->color_model == BC_YUV420P)
463 pict_tmp.data[0] = row_pointers[0];
464 pict_tmp.data[1] = row_pointers[1];
465 pict_tmp.data[2] = row_pointers[2];
466 pict_tmp.linesize[0] = width_i;
467 pict_tmp.linesize[1] = width_i / 2;
468 pict_tmp.linesize[2] = width_i / 2;
470 else
472 //printf(__FUNCTION__ " 1\n");
473 if(!codec->temp_frame)
475 codec->temp_frame = malloc(width_i * height_i * 3 / 2);
477 //printf(__FUNCTION__ " 1\n");
479 cmodel_transfer(0, /* Leave NULL if non existent */
480 row_pointers,
481 codec->temp_frame, /* Leave NULL if non existent */
482 codec->temp_frame + width_i * height_i,
483 codec->temp_frame + width_i * height_i + width_i * height_i / 4,
484 row_pointers[0], /* Leave NULL if non existent */
485 row_pointers[1],
486 row_pointers[2],
487 0, /* Dimensions to capture from input frame */
489 width,
490 height,
491 0, /* Dimensions to project on output frame */
493 width,
494 height,
495 file->color_model,
496 BC_YUV420P,
497 0, /* When transfering BC_RGBA8888 to non-alpha this is the background color in 0xRRGGBB hex */
498 width, /* For planar use the luma rowspan */
499 width_i);
500 //printf(__FUNCTION__ " 1\n");
502 pict_tmp.data[0] = codec->temp_frame;
503 pict_tmp.data[1] = codec->temp_frame + width_i * height_i;
504 pict_tmp.data[2] = codec->temp_frame + width_i * height_i + width_i * height_i / 4;
505 pict_tmp.linesize[0] = width_i;
506 pict_tmp.linesize[1] = width_i / 2;
507 pict_tmp.linesize[2] = width_i / 2;
511 //printf("encode 1\n");
512 if(codec->quantizer >= 0)
513 pict_tmp.quality = codec->quantizer;
514 bytes = avcodec_encode_video(codec->encoder_context,
515 codec->work_buffer,
516 codec->buffer_size,
517 &pict_tmp);
518 pthread_mutex_unlock(&encode_mutex);
519 //printf("encode 100\n");
521 quicktime_write_chunk_header(file, trak, &chunk_atom);
522 //printf(__FUNCTION__ " 1\n");
523 result = !quicktime_write_data(file,
524 codec->work_buffer,
525 bytes);
526 //printf(__FUNCTION__ " 1\n");
528 quicktime_write_chunk_footer(file,
529 trak,
530 vtrack->current_chunk,
531 &chunk_atom,
533 //printf(__FUNCTION__ " 1\n");
534 if(pict_tmp.key_frame)
535 quicktime_insert_keyframe(file,
536 vtrack->current_position,
537 track);
538 vtrack->current_chunk++;
540 //printf(__FUNCTION__ " 100\n");
545 return result;
550 static int set_parameter(quicktime_t *file,
551 int track,
552 char *key,
553 void *value)
555 quicktime_video_map_t *vtrack = &(file->vtracks[track]);
556 quicktime_div3_codec_t *codec = ((quicktime_codec_t*)vtrack->codec)->priv;
557 if(!strcasecmp(key, "div3_bitrate"))
558 codec->bitrate = *(int*)value;
559 else
560 if(!strcasecmp(key, "div3_bitrate_tolerance"))
561 codec->bitrate_tolerance = *(int*)value;
562 else
563 if(!strcasecmp(key, "div3_interlaced"))
564 codec->quantizer = *(int*)value;
565 else
566 if(!strcasecmp(key, "div3_gop_size"))
567 codec->gop_size = *(int*)value;
568 else
569 if(!strcasecmp(key, "div3_quantizer"))
570 codec->quantizer = *(int*)value;
571 else
572 if(!strcasecmp(key, "div3_fix_bitrate"))
573 codec->fix_bitrate = *(int*)value;
575 return 0;
579 void quicktime_init_codec_div3(quicktime_video_map_t *vtrack)
581 quicktime_div3_codec_t *codec;
582 ((quicktime_codec_t*)vtrack->codec)->priv = calloc(1, sizeof(quicktime_div3_codec_t));
583 ((quicktime_codec_t*)vtrack->codec)->delete_vcodec = delete_codec;
584 ((quicktime_codec_t*)vtrack->codec)->decode_video = decode;
585 ((quicktime_codec_t*)vtrack->codec)->encode_video = encode;
586 ((quicktime_codec_t*)vtrack->codec)->reads_colormodel = reads_colormodel;
587 ((quicktime_codec_t*)vtrack->codec)->writes_colormodel = writes_colormodel;
588 ((quicktime_codec_t*)vtrack->codec)->set_parameter = set_parameter;
590 codec = ((quicktime_codec_t*)vtrack->codec)->priv;
591 codec->derivative = CODEC_ID_MSMPEG4V3;
592 // codec->derivative = CODEC_ID_MPEG4;
593 codec->quantizer = -1;
601 void quicktime_init_codec_div4(quicktime_video_map_t *vtrack)
603 quicktime_div3_codec_t *codec;
604 ((quicktime_codec_t*)vtrack->codec)->priv = calloc(1, sizeof(quicktime_div3_codec_t));
605 ((quicktime_codec_t*)vtrack->codec)->delete_vcodec = delete_codec;
606 ((quicktime_codec_t*)vtrack->codec)->decode_video = decode;
607 ((quicktime_codec_t*)vtrack->codec)->encode_video = encode;
608 ((quicktime_codec_t*)vtrack->codec)->reads_colormodel = reads_colormodel;
609 ((quicktime_codec_t*)vtrack->codec)->writes_colormodel = writes_colormodel;
610 ((quicktime_codec_t*)vtrack->codec)->set_parameter = set_parameter;
612 codec = ((quicktime_codec_t*)vtrack->codec)->priv;
613 codec->derivative = CODEC_ID_MPEG4;
614 codec->quantizer = -1;