x264.c
来自「这个库实现了录象功能」· C语言 代码 · 共 933 行 · 第 1/2 页
C
933 行
/******************************************************************************* x264.c libquicktime - A library for reading and writing quicktime/avi/mp4 files. http://libquicktime.sourceforge.net Copyright (C) 2002 Heroine Virtual Ltd. Copyright (C) 2002-2007 Members of the libquicktime project. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA*******************************************************************************/ #include "lqt_private.h"#include <x264.h>#include <stdlib.h>#include <string.h>#include <quicktime/colormodels.h>#include "qtx264.h"#define LOG_DOMAIN "x264"// #define DUMP_CONFIG#ifdef DUMP_CONFIGstatic void dump_params(x264_param_t * params) { lqt_dump("X264 params:\n"); lqt_dump(" cpu: %08x\n", params->cpu); lqt_dump(" i_threads: %d\n", params->i_threads); lqt_dump(" i_width: %d\n", params->i_width); lqt_dump(" i_height: %d\n", params->i_height); lqt_dump(" i_csp: %d\n", params->i_csp); lqt_dump(" i_level_idc: %d\n", params->i_level_idc); lqt_dump(" i_frame_total: %d\n", params->i_frame_total); lqt_dump(" vui:\n"); lqt_dump(" i_sar_height: %d\n", params->vui.i_sar_height); lqt_dump(" i_sar_width: %d\n", params->vui.i_sar_width); lqt_dump(" i_overscan: %d\n", params->vui.i_overscan); lqt_dump(" i_vidformat: %d\n", params->vui.i_vidformat); lqt_dump(" b_fullrange: %d\n", params->vui.b_fullrange); lqt_dump(" i_colorprim: %d\n", params->vui.i_colorprim); lqt_dump(" i_transfer: %d\n", params->vui.i_transfer); lqt_dump(" i_colmatrix: %d\n", params->vui.i_colmatrix); lqt_dump(" i_chroma_loc: %d\n", params->vui.i_chroma_loc); lqt_dump(" fps: %d:%d\n", params->i_fps_num, params->i_fps_den); /* Bitstream parameters */ lqt_dump(" i_frame_reference: %d\n", params->i_frame_reference); // 1..16 lqt_dump(" i_keyint_min: %d\n", params->i_keyint_min); lqt_dump(" i_keyint_max: %d\n", params->i_keyint_max); lqt_dump(" i_scenecut_threshold: %d\n", params->i_scenecut_threshold); lqt_dump(" i_bframe: %d\n", params->i_bframe); // 0.. X264_BFRAME_MAX lqt_dump(" b_bframe_adaptive: %d\n", params->b_bframe_adaptive); lqt_dump(" i_bframe_bias: %d\n", params->i_bframe_bias); lqt_dump(" b_bframe_pyramid: %d\n", params->b_bframe_pyramid); lqt_dump(" b_deblocking_filter: %d\n", params->b_deblocking_filter); lqt_dump(" i_deblocking_filter_alphac0: %d\n", params->i_deblocking_filter_alphac0); // -6..6 lqt_dump(" i_deblocking_filter_beta: %d\n", params->i_deblocking_filter_beta); // -6..6 lqt_dump(" b_cabac: %d\n", params->b_cabac); lqt_dump(" i_cabac_init_idc: %d\n", params->i_cabac_init_idc); // 0..2 lqt_dump(" i_cqm_preset: %d\n", params->i_cqm_preset); lqt_dump(" psz_cqm_file: %s\n", params->psz_cqm_file); lqt_dump(" Analyze:\n"); // ORED value of X264_ANALYSE_I4x4, X264_ANALYSE_I8x8, X264_ANALYSE_PSUB16x16, X264_ANALYSE_PSUB8x8, // X264_ANALYSE_BSUB16x16 lqt_dump(" intra: %d\n", params->analyse.intra); lqt_dump(" inter: %d\n", params->analyse.inter); lqt_dump(" b_transform_8x8: %d\n", params->analyse.b_transform_8x8); lqt_dump(" b_weighted_bipred: %d\n", params->analyse.b_weighted_bipred); lqt_dump(" i_direct_mv_pred: %d\n", params->analyse.i_direct_mv_pred); lqt_dump(" i_chroma_qp_offset: %d\n", params->analyse.i_chroma_qp_offset); // X264_ME_DIA, X264_ME_HEX, X264_ME_UMH, X264_ME_ESA lqt_dump(" i_me_method: %d\n", params->analyse.i_me_method); lqt_dump(" i_me_range: %d\n", params->analyse.i_me_range); lqt_dump(" i_mv_range: %d\n", params->analyse.i_mv_range); lqt_dump(" i_subpel_refine: %d\n", params->analyse.i_subpel_refine); // 1..7 lqt_dump(" b_bidir_me: %d\n", params->analyse.b_bidir_me); lqt_dump(" b_chroma_me: %d\n", params->analyse.b_chroma_me); lqt_dump(" b_bframe_rdo: %d\n", params->analyse.b_bframe_rdo); lqt_dump(" b_mixed_references: %d\n", params->analyse.b_mixed_references); lqt_dump(" i_trellis: %d\n", params->analyse.i_trellis); // 0..2 lqt_dump(" b_fast_pskip: %d\n", params->analyse.b_fast_pskip); lqt_dump(" i_noise_reduction: %d\n", params->analyse.i_noise_reduction); // 0..1<<16 lqt_dump(" b_psnr: %d\n", params->analyse.b_psnr); lqt_dump(" Rate control:\n"); lqt_dump(" i_rc_method: %d\n", params->rc.i_rc_method); lqt_dump(" i_qp_constant: %d\n", params->rc.i_qp_constant); lqt_dump(" i_qp_min: %d\n", params->rc.i_qp_min); lqt_dump(" i_qp_max: %d\n", params->rc.i_qp_max); lqt_dump(" i_qp_step: %d\n", params->rc.i_qp_step); lqt_dump(" i_bitrate: %d\n", params->rc.i_bitrate);#if X264_BUILD < 54 lqt_dump(" i_rf_constant: %d\n", params->rc.i_rf_constant);#else lqt_dump(" f_rf_constant: %f\n", params->rc.f_rf_constant);#endif lqt_dump(" f_rate_tolerance: %f\n", params->rc.f_rate_tolerance); lqt_dump(" i_vbv_max_bitrate: %d\n", params->rc.i_vbv_max_bitrate); lqt_dump(" i_vbv_buffer_size: %d\n", params->rc.i_vbv_buffer_size); lqt_dump(" f_vbv_buffer_init: %f\n", params->rc.f_vbv_buffer_init); lqt_dump(" f_ip_factor: %f\n", params->rc.f_ip_factor); lqt_dump(" f_pb_factor: %f\n", params->rc.f_pb_factor); }#endif // DUMP_CONFIG/* * x264 encoder. * NAL reformatting stuff taken from ffmpeg/libavformat/movenc.c */ typedef struct { x264_param_t params; x264_t *enc; x264_picture_t pic; int initialized; /* For raw x264 output */ uint8_t * work_buffer; int work_buffer_size; /* Reformatted buffer */ uint8_t * work_buffer_1; int work_buffer_alloc_1; int total_passes; int pass; char * stats_filename; } quicktime_x264_codec_t;static int delete_codec(quicktime_video_map_t *vtrack) { quicktime_x264_codec_t *codec = ((quicktime_codec_t*)vtrack->codec)->priv; if(codec->enc) x264_encoder_close(codec->enc); if(codec->stats_filename) free(codec->stats_filename); free(codec); return 0; }static intencode_nals(uint8_t *buf, int size, x264_nal_t *nals, int nnal) { uint8_t *p = buf; int i; int s; for(i = 0; i < nnal; i++) { s = x264_nal_encode(p, &size, 1, nals + i); if(s < 0) return -1; p += s; } return p - buf; }static uint8_t *avc_find_startcode( uint8_t *p, uint8_t *end ) { uint8_t *a = p + 4 - ((long)p & 3); for( end -= 3; p < a && p < end; p++ ) { if( p[0] == 0 && p[1] == 0 && p[2] == 1 ) return p; } for( end -= 3; p < end; p += 4 ) { uint32_t x = *(uint32_t*)p; // if( (x - 0x01000100) & (~x) & 0x80008000 ) // little endian // if( (x - 0x00010001) & (~x) & 0x00800080 ) // big endian if( (x - 0x01010101) & (~x) & 0x80808080 ) { // generic if( p[1] == 0 ) { if( p[0] == 0 && p[2] == 1 ) return p; if( p[2] == 0 && p[3] == 1 ) return p+1; } if( p[3] == 0 ) { if( p[2] == 0 && p[4] == 1 ) return p+2; if( p[4] == 0 && p[5] == 1 ) return p+3; } } } for( end += 3; p < end; p++ ) { if( p[0] == 0 && p[1] == 0 && p[2] == 1 ) return p; } return end + 3; }static int avc_parse_nal_units(uint8_t *src, int src_size, uint8_t ** _dst, int * dst_alloc) { uint8_t *p = src; uint8_t *end = p + src_size; uint8_t *nal_start, *nal_end; uint8_t * dst, * ret_ptr; int ret_size = 0; uint32_t nal_size; dst = *_dst; /* Get the size */ nal_start = avc_find_startcode(p, end); while (nal_start < end) { while(!*(nal_start++)); nal_end = avc_find_startcode(nal_start, end); ret_size += 4 + (int)(nal_end - nal_start); nal_start = nal_end; } if(ret_size > *dst_alloc) { *dst_alloc = ret_size + 1024; dst = realloc(dst, *dst_alloc); } /* Copy */ ret_ptr = dst; nal_start = avc_find_startcode(p, end); while (nal_start < end) { while(!*(nal_start++)); nal_end = avc_find_startcode(nal_start, end); nal_size = nal_end - nal_start; ret_ptr[0] = (nal_size >> 24) & 0xff; ret_ptr[1] = (nal_size >> 16) & 0xff; ret_ptr[2] = (nal_size >> 8) & 0xff; ret_ptr[3] = (nal_size) & 0xff; ret_ptr += 4; memcpy(ret_ptr, nal_start, nal_size); ret_ptr += nal_size; nal_start = nal_end; } *_dst = dst; return ret_size; }static uint8_t * create_avcc_atom(quicktime_x264_codec_t * codec, int * ret_size) { int i; x264_nal_t *nal; int nnal; uint8_t * ret, *ret_ptr; uint8_t * tmp_buf, *tmp_buf_1 = (uint8_t*)0; int tmp_buf_alloc_1 = 0; int tmp_size; int tmp_size_1; uint8_t * ptr, *ptr_end; uint32_t nal_size; uint32_t sps_size=0, pps_size=0; uint8_t *sps=0, *pps=0; uint8_t nal_type; x264_encoder_headers(codec->enc, &nal, &nnal); tmp_size = 0; /* 5 bytes NAL header + worst case escaping */ for(i = 0; i < nnal; i++) tmp_size += 5 + nal[i].i_payload * 4 / 3; tmp_buf = malloc(tmp_size); tmp_size = encode_nals(tmp_buf, tmp_size, nal, nnal); tmp_size_1 = avc_parse_nal_units(tmp_buf, tmp_size, &tmp_buf_1, &tmp_buf_alloc_1); /* Look for sps and pps */ ptr = tmp_buf_1; ptr_end = tmp_buf_1 + tmp_size_1; /* look for sps and pps */ while(ptr < ptr_end) { nal_size = ((uint32_t)ptr[0] << 24) | ((uint32_t)ptr[1] << 16) | ((uint32_t)ptr[2] << 8) | (uint32_t)ptr[3]; nal_type = ptr[4] & 0x1f; if (nal_type == 7) { /* SPS */ sps = ptr + 4; sps_size = nal_size; } else if (nal_type == 8) { /* PPS */ pps = ptr + 4; pps_size = nal_size; } ptr += nal_size + 4; } *ret_size = 6 + // Initial bytes 2 + // sps_size sps_size + // sps 1 + // num_pps 2 + // pps_size pps_size; // pps ret = malloc(*ret_size); ret_ptr = ret; /* Start encoding */ *(ret_ptr++) = 0x01; /* Version */ *(ret_ptr++) = 0x4d; /* 77, profile */ *(ret_ptr++) = 0x40; /* 64, profile compat */ *(ret_ptr++) = 0x1E; /* 30, level (31?) */ *(ret_ptr++) = 0xFF; /* 6 bits reserved (111111) + 2 bits nal size length - 1 (11) */ *(ret_ptr++) = 0xE1; /* 3 bits reserved (111) + 5 bits number of sps (00001) */ /* sps_size */ ret_ptr[0] = (sps_size >> 8) & 0xff; ret_ptr[1] = sps_size & 0xff; ret_ptr += 2; /* sps */ memcpy(ret_ptr, sps, sps_size); ret_ptr += sps_size; /* num_pps */ *(ret_ptr++) = 0x01; /* pps_size */ ret_ptr[0] = (pps_size >> 8) & 0xff; ret_ptr[1] = pps_size & 0xff; ret_ptr += 2; /* pps */ memcpy(ret_ptr, pps, pps_size); ret_ptr += pps_size; free(tmp_buf); free(tmp_buf_1); return ret; }static int flush_frame(quicktime_t *file, int track, x264_picture_t * pic_in) { int result; quicktime_atom_t chunk_atom; x264_nal_t *nal; int nnal; x264_picture_t pic_out; int encoded_size; quicktime_video_map_t *vtrack = &(file->vtracks[track]); quicktime_x264_codec_t *codec = ((quicktime_codec_t*)vtrack->codec)->priv; quicktime_trak_t *trak = vtrack->track; pic_out.i_pts = 0; /* Encode frames, get nals */ if(x264_encoder_encode(codec->enc, &nal, &nnal, pic_in, &pic_out)) return 0; /* Encode nals -> get h264 stream */ encoded_size = encode_nals(codec->work_buffer, codec->work_buffer_size, nal, nnal); /* Reformat nals */ encoded_size = avc_parse_nal_units(codec->work_buffer, encoded_size, &codec->work_buffer_1, &codec->work_buffer_alloc_1); if(encoded_size < 0) return 0; vtrack->coded_timestamp = pic_out.i_pts; if(encoded_size) { quicktime_write_chunk_header(file, trak, &chunk_atom); result = !quicktime_write_data(file, codec->work_buffer_1, encoded_size); quicktime_write_chunk_footer(file, trak, vtrack->current_chunk, &chunk_atom, 1); if(pic_out.i_type == X264_TYPE_IDR) quicktime_insert_keyframe(file, vtrack->current_chunk-1, track); vtrack->current_chunk++; return 1; } return 0; }static int set_pass_x264(quicktime_t *file, int track, int pass, int total_passes, const char * stats_file) { quicktime_video_map_t *vtrack = &(file->vtracks[track]); quicktime_x264_codec_t *codec = ((quicktime_codec_t*)vtrack->codec)->priv; codec->total_passes = total_passes; codec->pass = pass; codec->stats_filename = malloc(strlen(stats_file)+1); strcpy(codec->stats_filename, stats_file); return 1; }
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?