+++ /dev/null
-#include "libavcodec/avcodec.h"
-#include "colormodels.h"
-#include "funcprotos.h"
-#include "qtffmpeg.h"
-#include "quicktime.h"
-#include "workarounds.h"
-#include "x264.h"
-
-#include <string.h>
-
-// This generates our own header using fixed parameters
-//#define MANUAL_HEADER
-
-
-typedef struct
-{
-// Encoder side
- x264_t *encoder[FIELDS];
- x264_picture_t *pic[FIELDS];
- x264_param_t param;
-
- int encode_initialized[FIELDS];
-
-// Temporary storage for color conversions
- char *temp_frame;
-// Storage of compressed data
- unsigned char *work_buffer;
-// Amount of data in work_buffer
- int buffer_size;
- int total_fields;
-// Set by flush
- int flushing;
-
-// Decoder side
- quicktime_ffmpeg_t *decoder;
-
-} quicktime_h264_codec_t;
-
-static pthread_mutex_t h264_lock = PTHREAD_MUTEX_INITIALIZER;
-
-
-// Direct copy routines
-int quicktime_h264_is_key(unsigned char *data, long size, char *codec_id)
-{
- return 0;
-}
-
-
-static void delete_codec(quicktime_video_map_t *vtrack)
-{
- int i;
- quicktime_h264_codec_t *codec = ((quicktime_codec_t*)vtrack->codec)->priv;
-
- for(i = 0; i < codec->total_fields; i++) {
- if( !codec->encode_initialized[i]) continue;
- pthread_mutex_lock(&h264_lock);
- if(codec->pic[i]) {
- x264_picture_clean(codec->pic[i]);
- free(codec->pic[i]);
- }
- if(codec->encoder[i]) {
- x264_encoder_close(codec->encoder[i]);
- }
- pthread_mutex_unlock(&h264_lock);
- }
-
- if(codec->temp_frame) free(codec->temp_frame);
- if(codec->work_buffer) free(codec->work_buffer);
- if(codec->decoder) quicktime_delete_ffmpeg(codec->decoder);
- free(codec);
-}
-
-
-
-static int encode(quicktime_t *file, unsigned char **row_pointers, int track)
-{
-// int64_t offset = quicktime_position(file);
- quicktime_video_map_t *vtrack = &(file->vtracks[track]);
- quicktime_h264_codec_t *codec = ((quicktime_codec_t*)vtrack->codec)->priv;
- quicktime_trak_t *trak = vtrack->track;
- int width = quicktime_video_width(file, track);
- int height = quicktime_video_height(file, track);
- int w_2 = quicktime_quantize2(width);
-// ffmpeg interprets the codec height as the presentation height
- int h_2 = quicktime_quantize2(height);
- int i;
- int result = -1;
- int is_keyframe = 0;
- int frame_number = vtrack->current_position / codec->total_fields;
- int current_field = vtrack->current_position % codec->total_fields;
- quicktime_atom_t chunk_atom;
- unsigned char header[1024];
- int header_size = 0;
- int got_pps = 0;
- int got_sps = 0;
- quicktime_avcc_t *avcc = &trak->mdia.minf.stbl.stsd.table[0].avcc;
-
- pthread_mutex_lock(&h264_lock);
-
- if(!codec->encode_initialized[current_field])
- {
- codec->encode_initialized[current_field] = 1;
- codec->param.i_width = w_2;
- codec->param.i_height = h_2;
- codec->param.i_fps_num = quicktime_frame_rate_n(file, track);
- codec->param.i_fps_den = quicktime_frame_rate_d(file, track);
-
-// Reset quantizer if fixed bitrate
- x264_param_t default_params;
- x264_param_default(&default_params);
- if(codec->param.rc.i_qp_constant)
- {
- codec->param.rc.i_qp_constant = default_params.rc.i_qp_constant;
- codec->param.rc.i_qp_min = default_params.rc.i_qp_min;
- codec->param.rc.i_qp_max = default_params.rc.i_qp_max;
- }
-
- if(file->cpus > 1)
- {
- codec->param.i_threads = file->cpus;
- }
-
- codec->encoder[current_field] = x264_encoder_open(&codec->param);
- codec->pic[current_field] = calloc(1, sizeof(x264_picture_t));
- x264_picture_init(codec->pic[current_field]);
-//printf("encode 1 %d %d\n", codec->param.i_width, codec->param.i_height);
- x264_picture_alloc(codec->pic[current_field], X264_CSP_I420,
- codec->param.i_width, codec->param.i_height);
- }
-
- x264_picture_t *pic = codec->pic[current_field];
- pic->i_type = X264_TYPE_AUTO;
- pic->i_qpplus1 = X264_QP_AUTO;
- pic->i_pts = frame_number;
-
- codec->buffer_size = 0;
- int allocation = w_2 * h_2 * 3 + 100;
- if( !codec->work_buffer ) {
- codec->work_buffer = calloc(1, allocation);
- }
-
- x264_picture_t pic_out;
- x264_nal_t *nals;
- int nnal = 0;
- x264_t *h = codec->encoder[current_field];
-
- if( !codec->flushing ) {
- if( !row_pointers ) {
- bzero(pic->img.plane[0], w_2 * h_2);
- bzero(pic->img.plane[1], w_2 * h_2 / 4);
- bzero(pic->img.plane[2], w_2 * h_2 / 4);
- }
- else if( file->color_model == BC_YUV420P ) {
- memcpy(pic->img.plane[0], row_pointers[0], w_2 * h_2);
- memcpy(pic->img.plane[1], row_pointers[1], w_2 * h_2 / 4);
- memcpy(pic->img.plane[2], row_pointers[2], w_2 * h_2 / 4);
- }
- else {
-//printf("encode 2 %p %p %p\n", pic->img.plane[0], pic->img.plane[1], pic->img.plane[2]);
- cmodel_transfer(0, row_pointers,
- pic->img.plane[0], pic->img.plane[1], pic->img.plane[2],
- row_pointers[0], row_pointers[1], row_pointers[2],
- 0, 0, width, height, 0, 0, width, height,
- file->color_model, BC_YUV420P,
- 0, width, pic->img.i_stride[0]);
- }
-
- result = x264_encoder_encode(h, &nals, &nnal, pic, &pic_out);
- if( result < 0 )
- printf("frame_num %d: nals=%d, ret=%d\n", frame_number, nnal, result);
- }
- else if( x264_encoder_delayed_frames(h) > 0 ) {
- result = x264_encoder_encode(h, &nals, &nnal, 0, &pic_out);
- if( result < 0 )
- printf("flushing %d: nals=%d, ret=%d\n", frame_number, nnal, result);
- }
-//printf("encode %d nnal=%d\n", __LINE__, nnal);
-
- for( i = 0; i < nnal; ++i ) {
- int size = nals[i].i_payload;
-//printf("encode %d size=%d\n", __LINE__, size);
- if(size + codec->buffer_size > allocation) {
- printf("qth264.c %d: overflow size=%d allocation=%d\n",
- __LINE__, size, allocation);
- break;
- }
- unsigned char *ptr = codec->work_buffer + codec->buffer_size;
- memcpy(ptr, nals[i].p_payload, size);
- codec->buffer_size += size;
- if( avcc->data_size ) continue;
-// Snoop NAL for avc
- ptr += 4; size -= 4;
-// Synthesize header.
-// Hopefully all the parameter set NAL's are present in the first frame.
- if( !header_size ) {
- header[header_size++] = 0x01;
- header[header_size++] = 0x4d;
- header[header_size++] = 0x40;
- header[header_size++] = 0x1f;
- header[header_size++] = 0xff;
- header[header_size++] = 0xe1;
- }
-
- int nal_type = (*ptr & 0x1f);
-// Picture parameter or sequence parameter set
- switch( nal_type ) {
- case 0x07:
- if( got_sps ) continue;
- got_sps = 1;
- break;
- case 0x08:
- if( got_pps ) continue;
- got_pps = 1;
- header[header_size++] = 0x1; // Number of sps nal's.
- break;
- default:
- continue;
- }
-
- header[header_size++] = size >> 8;
- header[header_size++] = size;
- memcpy(&header[header_size], ptr, size);
- header_size += size;
- if( !got_sps || !got_pps ) continue;
-// printf("encode %d\n", __LINE__);
-// { int j; for(j = 0; j < header_size; j++) printf("%02x ", header[j]); }
-// printf("\n");
-// Write header
- quicktime_set_avcc_header(avcc, header, header_size);
- }
-
- pthread_mutex_unlock(&h264_lock);
-
- if( codec->buffer_size > 0 ) {
- if(pic_out.i_type == X264_TYPE_IDR ||
- pic_out.i_type == X264_TYPE_I) {
- is_keyframe = 1;
- }
-
- quicktime_write_chunk_header(file, trak, &chunk_atom);
- result = !quicktime_write_data(file,
- (char*)codec->work_buffer,
- codec->buffer_size);
- quicktime_write_chunk_footer(file, trak,
- vtrack->current_chunk, &chunk_atom, 1);
-
- if(is_keyframe) {
- quicktime_insert_keyframe(file,
- vtrack->current_position,
- track);
- }
-
- vtrack->current_chunk++;
- }
- return result >= 0 ? 0 : -1;
-}
-
-
-
-
-static int decode(quicktime_t *file, unsigned char **row_pointers, int track)
-{
- quicktime_video_map_t *vtrack = &(file->vtracks[track]);
- quicktime_trak_t *trak = vtrack->track;
- quicktime_h264_codec_t *codec = ((quicktime_codec_t*)vtrack->codec)->priv;
- quicktime_stsd_table_t *stsd_table = &trak->mdia.minf.stbl.stsd.table[0];
- int width = trak->tkhd.track_width;
- int height = trak->tkhd.track_height;
-
- if(!codec->decoder)
- codec->decoder = quicktime_new_ffmpeg(file->cpus,
- codec->total_fields, CODEC_ID_H264, width, height, stsd_table);
- return !codec->decoder ? 1 :
- quicktime_ffmpeg_decode(codec->decoder, file, row_pointers, track);
-}
-
-static void flush(quicktime_t *file, int track)
-{
- quicktime_video_map_t *vtrack = &(file->vtracks[track]);
- quicktime_trak_t *trak = vtrack->track;
- quicktime_h264_codec_t *codec = ((quicktime_codec_t*)vtrack->codec)->priv;
-// trak->mdia.minf.stbl.stsd.table[0].version = 1;
-// trak->mdia.minf.stbl.stsd.table[0].revision = 1;
- quicktime_avcc_t *avcc = &trak->mdia.minf.stbl.stsd.table[0].avcc;
- if( !avcc->data_size )
- encode(file, 0, track);
- codec->flushing = 1;
- while( !encode(file, 0, track) );
-}
-
-
-
-static int reads_colormodel(quicktime_t *file,
- int colormodel,
- int track)
-{
- return (colormodel == BC_YUV420P);
-}
-
-static int writes_colormodel(quicktime_t *file,
- int colormodel,
- int track)
-{
- return (colormodel == BC_YUV420P);
-}
-
-static int set_parameter(quicktime_t *file,
- int track,
- char *key,
- void *value)
-{
- quicktime_video_map_t *vtrack = &(file->vtracks[track]);
- char *compressor = quicktime_compressor(vtrack->track);
-
- if(quicktime_match_32(compressor, QUICKTIME_H264) ||
- quicktime_match_32(compressor, QUICKTIME_HV64))
- {
- quicktime_h264_codec_t *codec = ((quicktime_codec_t*)vtrack->codec)->priv;
- if(!strcasecmp(key, "h264_bitrate"))
- {
- if(quicktime_match_32(compressor, QUICKTIME_H264))
- codec->param.rc.i_bitrate = *(int*)value;
- else
- codec->param.rc.i_bitrate = *(int*)value / 2;
- }
- else
- if(!strcasecmp(key, "h264_quantizer"))
- {
- codec->param.rc.i_qp_constant =
- codec->param.rc.i_qp_min =
- codec->param.rc.i_qp_max = *(int*)value;
- }
- else
- if(!strcasecmp(key, "h264_fix_bitrate"))
- {
- codec->param.rc.i_qp_constant = (*(int*)value) / 1000;
- }
- }
- return 0;
-}
-
-static quicktime_h264_codec_t* init_common(quicktime_video_map_t *vtrack,
- char *compressor,
- char *title,
- char *description)
-{
- quicktime_codec_t *codec_base = (quicktime_codec_t*)vtrack->codec;
- quicktime_h264_codec_t *codec;
-
- codec_base->priv = calloc(1, sizeof(quicktime_h264_codec_t));
- codec_base->delete_vcodec = delete_codec;
- codec_base->decode_video = decode;
- codec_base->encode_video = encode;
- codec_base->flush = flush;
- codec_base->reads_colormodel = reads_colormodel;
- codec_base->writes_colormodel = writes_colormodel;
- codec_base->set_parameter = set_parameter;
- codec_base->fourcc = compressor;
- codec_base->title = title;
- codec_base->desc = description;
-
-
- codec = (quicktime_h264_codec_t*)codec_base->priv;
- x264_param_default(&codec->param);
- codec->param.rc.i_rc_method = X264_RC_CQP;
-// codec->param.i_log_level = 99;
- return codec;
-}
-
-
-void quicktime_init_codec_h264(quicktime_video_map_t *vtrack)
-{
- quicktime_h264_codec_t *result = init_common(vtrack,
- QUICKTIME_H264,
- "H.264",
- "H.264");
- result->total_fields = 1;
-}
-
-
-// field based H.264
-void quicktime_init_codec_hv64(quicktime_video_map_t *vtrack)
-{
- quicktime_h264_codec_t *result = init_common(vtrack,
- QUICKTIME_HV64,
- "Dual H.264",
- "H.264 with two streams alternating every other frame. (Not standardized)");
- result->total_fields = 2;
-}
-
-
-
-