static int Encode_frame( x264_t *h, hnd_t hout, x264_picture_t *pic ) { x264_picture_t pic_out; x264_nal_t *nal; int i_nal, i; int i_file = 0; if( x264_encoder_encode( h, &nal, &i_nal, pic, &pic_out ) < 0 ) { fprintf( stderr, "x264_encoder_encode failed\n" ); } for( i = 0; i < i_nal; i++ ) { int i_size; int i_data; i_data = DATA_MAX; if( ( i_size = x264_nal_encode( data, &i_data, 1, &nal[i] ) ) > 0 ) { i_file += p_write_nalu( hout, data, i_size ); } else if( i_size < 0 ) { fprintf( stderr, "need to increase buffer size (size=%d)\n", -i_size ); } } if (i_nal) p_set_eop( hout, &pic_out ); return i_file; }
int X264Encoder::Encode(unsigned char* szYUVFrame, unsigned char* outBuf, int& outLen, bool& isKeyframe) { // 可以优化为m_pic中保存一个指针,直接执行szYUVFrame memcpy(m_pic.img.plane[0], szYUVFrame, m_param.i_width * m_param.i_height*3 / 2); //m_pic.img.plane[0] = szYUVFrame; m_param.i_frame_total++; m_pic.i_pts = (int64_t)m_param.i_frame_total * m_param.i_fps_den; if (isKeyframe) m_pic.i_type = X264_TYPE_IDR; else m_pic.i_type = X264_TYPE_AUTO; x264_picture_t pic_out; x264_nal_t *nal=0; int i_nal, i; // nal的个数 if( x264_encoder_encode( m_h, &nal, &i_nal, &m_pic, &pic_out ) < 0 ) { //fprintf( stderr, "x264 [error]: x264_encoder_encode failed\n" ); return -1; } char* tmpbuf = NULL; char* ptmpbuf = NULL; if (pps_ == NULL) { tmpbuf = (char*)malloc(m_param.i_width * m_param.i_height * 100); ptmpbuf = tmpbuf; } int maxlen = outLen; outLen = 0; for( i = 0; i < i_nal; i++ ) { int i_size = 0; x264_nal_encode(outBuf+outLen, &i_size, 1, &nal[i] ); if (ptmpbuf) { memcpy(ptmpbuf, outBuf+outLen, i_size); ptmpbuf += i_size; } // 将起始码0x00000001,替换为nalu的大小 UI32ToBytes((char*)(outBuf+outLen), i_size-4); outLen += i_size; } if (tmpbuf) { FindSpsAndPPsFromBuf(tmpbuf, ptmpbuf-tmpbuf); free(tmpbuf); } isKeyframe = (pic_out.i_type == X264_TYPE_IDR); return 0; }
static int encode_nals(uint8_t *buf, int size, x264_nal_t *nals, int nnal){ uint8_t *p = buf; int i; for(i = 0; i < nnal; i++){ int s = x264_nal_encode(p, &size, 1, nals + i); if(s < 0) return -1; p += s; } return p - buf; }
//FILE* ff1 ; int H264EncWrapper::Encode(unsigned char* szYUVFrame, TNAL*& pNALArray, int& iNalNum) { // 可以优化为m_pic中保存一个指针,直接执行szYUVFrame memcpy(m_pic.img.plane[0], szYUVFrame, m_param.i_width * m_param.i_height*3 / 2); m_pic.i_pts = (int64_t)m_iFrameNum * m_param.i_fps_den; x264_picture_t pic_out; x264_nal_t *nal; int i_nal, i; // nal的个数 if( x264_encoder_encode( m_h, &nal, &i_nal, &m_pic, &pic_out ) < 0 ) { fprintf( stderr, "x264 [error]: x264_encoder_encode failed\n" ); return -1; } int i_size = 0; pNALArray = new TNAL[i_nal]; memset(pNALArray, 0, i_nal+1); for( i = 0; i < i_nal; i++ ) { if( m_iBufferSize < nal[i].i_payload * 3/2 + 4 ) { m_iBufferSize = nal[i].i_payload * 2 + 4; my_free( m_pBuffer ); m_pBuffer = (uint8_t*)my_malloc( m_iBufferSize ); } i_size = m_iBufferSize; x264_nal_encode( m_pBuffer, &i_size, 1, &nal[i] ); //DEBUG_LOG(INF, "Encode frame[%d], NAL[%d], length = %d, ref_idc = %d, type = %d", // m_iFrameNum, i, i_size, nal[i].i_ref_idc, nal[i].i_type); //printf("Encode frame[%d], NAL[%d], length = %d, ref_idc = %d, type = %d\n", // m_iFrameNum, i, i_size, nal[i].i_ref_idc, nal[i].i_type); //fwrite(m_pBuffer, 1, i_size, ff1); //去掉buffer中前面的 00 00 00 01 才是真正的nal unit pNALArray[i].size = i_size; pNALArray[i].data = new unsigned char[i_size]; memcpy(pNALArray[i].data, m_pBuffer, i_size); } iNalNum = i_nal; m_iFrameNum++; return 0; }
static int x264_encode_frame (x264_t *h, void *handle, x264_picture_t *pic) { x264_picture_t pic_out; x264_nal_t *nal; int i_nal; int i; int i_file = 0; /* Do not force any parameters */ if (pic) { pic->i_type = X264_TYPE_AUTO; pic->i_qpplus1 = 0; } if (x264_encoder_encode (h, &nal, &i_nal, pic, &pic_out) < 0) { fprintf (stderr, _("x264_encoder_encode failed\n")); } for (i = 0; i < i_nal; i++) { int i_size; int i_data; i_data = DATA_MAX; if ((i_size = x264_nal_encode (data, &i_data, 1, &nal[i])) > 0 ) { i_file += p_write_nalu (handle, data, i_size); } else if (i_size < 0) { fprintf (stderr, _("need to increase buffer size (size=%d)\n"), -i_size); } } if (i_nal) p_set_eop (handle, &pic_out); return i_file; }
int main(int argc, char* argv[]){ x264_param_t param; x264_t *h = NULL; x264_picture_t pic_in; x264_picture_t pic_out; x264_nal_t *nal; uint8_t *data = NULL; int widthXheight = width * height; int frame_size = width * height * 1.5; int read_sum = 0, write_sum = 0; int frames = 0; int i, rnum, i_size; x264_nal_t* pNals = NULL; x264_param_default(¶m); param.i_width = width; param.i_height = height; param.i_bframe = 3; param.i_fps_num = 25; param.i_fps_den = 1; param.b_vfr_input = 0; param.i_keyint_max = 250; param.rc.i_bitrate = 1500; param.i_scenecut_threshold = 40; param.i_level_idc = 51; x264_param_apply_profile(¶m, "high"); h = x264_encoder_open( ¶m ); // printf("param.rc.i_qp_min=%d, param.rc.i_qp_max=%d, param.rc.i_qp_step=%d param.rc.i_qp_constant=%d param.rc.i_rc_method=%d\n", // param.rc.i_qp_min, param.rc.i_qp_max, param.rc.i_qp_step, param.rc.i_qp_constant, param.rc.i_rc_method); printf("param:%s\n", x264_param2string(¶m, 1)); x264_picture_init( &pic_in ); x264_picture_alloc(&pic_in, X264_CSP_YV12, width, height); pic_in.img.i_csp = X264_CSP_YV12; pic_in.img.i_plane = 3; data = (uint8_t*)malloc(0x400000); FILE* fpr = fopen(MFILE ".yuv", "rb"); FILE* fpw1 = fopen(MFILE".szhu.h264", "wb"); // FILE* fpw2 = fopen(MFILE".h264", "wb"); if(!fpr || !fpw1 ) { printf("file open failed\n"); return -1; } while(!feof(fpr)){ rnum = fread(data, 1, frame_size, fpr); if(rnum != frame_size){ printf("read file failed\n"); break; } memcpy(pic_in.img.plane[0], data, widthXheight); memcpy(pic_in.img.plane[1], data + widthXheight, widthXheight >> 2); memcpy(pic_in.img.plane[2], data + widthXheight + (widthXheight >> 2), widthXheight >> 2); read_sum += rnum; frames ++; // printf("read frames=%d %.2fMB write:%.2fMB\n", frames, read_sum * 1.0 / 0x100000, write_sum * 1.0 / 0x100000); int i_nal; int i_frame_size = 0; if(0 && frames % 12 == 0){ pic_in.i_type = X264_TYPE_I; }else{ pic_in.i_type = X264_TYPE_AUTO; } i_frame_size = x264_encoder_encode( h, &nal, &i_nal, &pic_in, &pic_out ); if(i_frame_size <= 0){ //printf("\t!!!FAILED encode frame \n"); }else{ fwrite(nal[0].p_payload, 1, i_frame_size, fpw1); // printf("\t+++i_frame_size=%d\n", i_frame_size); write_sum += i_frame_size; } #if 0 for(i = 0; i < i_nal; i ++){ i_size = nal[i].i_payload; // fwrite(nal[i].p_payload, 1, nal[i].i_payload, fpw1); fwrite(nal[i].p_payload, 1, i_frame_size, fpw1); x264_nal_encode(h, data, &nal[i]); if(i_size != nal[i].i_payload){ printf("\t\ti_size=%d nal[i].i_payload=%d\n", i_size, nal[i].i_payload); } fwrite(data, 1, nal[i].i_payload, fpw2); } #endif } free(data); x264_picture_clean(&pic_in); x264_picture_clean(&pic_out); if(h){ x264_encoder_close(h); h = NULL; } fclose(fpw1); // fclose(fpw2); fclose(fpr); printf("h=0x%X", h); return 0; }
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 = 0; int bytes = 0; int is_keyframe = 0; 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); #if X264_BUILD >= 48 codec->param.rc.i_rc_method = X264_RC_CQP; #endif // Reset quantizer if fixed bitrate x264_param_t default_params; x264_param_default(&default_params); #if X264_BUILD < 48 if(codec->param.rc.b_cbr) #else if(codec->param.rc.i_qp_constant) #endif { 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)); //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); } codec->pic[current_field]->i_type = X264_TYPE_AUTO; codec->pic[current_field]->i_qpplus1 = 0; if(codec->header_only) { bzero(codec->pic[current_field]->img.plane[0], w_2 * h_2); bzero(codec->pic[current_field]->img.plane[1], w_2 * h_2 / 4); bzero(codec->pic[current_field]->img.plane[2], w_2 * h_2 / 4); } else if(file->color_model == BC_YUV420P) { memcpy(codec->pic[current_field]->img.plane[0], row_pointers[0], w_2 * h_2); memcpy(codec->pic[current_field]->img.plane[1], row_pointers[1], w_2 * h_2 / 4); memcpy(codec->pic[current_field]->img.plane[2], row_pointers[2], w_2 * h_2 / 4); } else { //printf("encode 2 %p %p %p\n", codec->pic[current_field]->img.plane[0], codec->pic[current_field]->img.plane[1], codec->pic[current_field]->img.plane[2]); cmodel_transfer(0, /* Leave NULL if non existent */ row_pointers, codec->pic[current_field]->img.plane[0], /* Leave NULL if non existent */ codec->pic[current_field]->img.plane[1], codec->pic[current_field]->img.plane[2], row_pointers[0], /* Leave NULL if non existent */ row_pointers[1], row_pointers[2], 0, /* Dimensions to capture from input frame */ 0, width, height, 0, /* Dimensions to project on output frame */ 0, width, height, file->color_model, BC_YUV420P, 0, /* When transfering BC_RGBA8888 to non-alpha this is the background color in 0xRRGGBB hex */ width, /* For planar use the luma rowspan */ codec->pic[current_field]->img.i_stride[0]); } x264_picture_t pic_out; x264_nal_t *nals; int nnal = 0; do { x264_encoder_encode(codec->encoder[current_field], &nals, &nnal, codec->pic[current_field], &pic_out); //printf("encode %d nnal=%d\n", __LINE__, nnal); } while(codec->header_only && !nnal); int allocation = w_2 * h_2 * 3; if(!codec->work_buffer) { codec->work_buffer = calloc(1, allocation); } codec->buffer_size = 0; //printf("encode %d nnal=%d\n", __LINE__, nnal); for(i = 0; i < nnal; i++) { #if X264_BUILD >= 76 int size = nals[i].i_payload; memcpy(codec->work_buffer + codec->buffer_size, nals[i].p_payload, nals[i].i_payload); #else int size_return = 0; int size = x264_nal_encode(codec->work_buffer + codec->buffer_size, &size_return, 1, nals + i); #endif unsigned char *ptr = codec->work_buffer + codec->buffer_size; //printf("encode %d size=%d\n", __LINE__, size); if(size > 0) { if(size + codec->buffer_size > allocation) { printf("qth264.c %d: overflow size=%d allocation=%d\n", __LINE__, size, allocation); } // Size of NAL for avc uint64_t avc_size = size - 4; // Synthesize header. // Hopefully all the parameter set NAL's are present in the first frame. if(!avcc->data_size) { if(header_size < 6) { 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[4] & 0x1f); // Picture parameter or sequence parameter set if(nal_type == 0x7 && !got_sps) { got_sps = 1; header[header_size++] = (avc_size & 0xff00) >> 8; header[header_size++] = (avc_size & 0xff); memcpy(&header[header_size], ptr + 4, avc_size); header_size += avc_size; } else if(nal_type == 0x8 && !got_pps) { got_pps = 1; // Number of sps nal's. header[header_size++] = 0x1; header[header_size++] = (avc_size & 0xff00) >> 8; header[header_size++] = (avc_size & 0xff); memcpy(&header[header_size], ptr + 4, avc_size); header_size += avc_size; } // Write header if(got_sps && got_pps) { /* * printf("encode %d\n", __LINE__); * int j; * for(j = 0; j < header_size; j++) * { * printf("%02x ", header[j]); * } * printf("\n"); */ quicktime_set_avcc_header(avcc, header, header_size); } }
bool CX264VideoEncoder::GetEsConfig (uint8_t **ppEsConfig, uint32_t *pEsConfigLen) { #ifdef DEBUG_H264 debug_message("Getting es config for x264"); #endif CHECK_AND_FREE(Profile()->m_videoMpeg4Config); Profile()->m_videoMpeg4ConfigLength = 0; x264_nal_t *nal; int nal_num; if (x264_encoder_headers(m_h, &nal, &nal_num) != 0) { error_message("x264 - can't create headers"); StopEncoder(); return false; } uint8_t *seqptr = m_vopBuffer; uint8_t *picptr = m_vopBuffer; uint32_t seqlen = 0, piclen = 0; bool found_seq = false, found_pic = false; if (m_vopBuffer == NULL) { m_vopBuffer = (u_int8_t*)malloc(Profile()->m_videoMaxVopSize); } uint8_t *vopBuffer = m_vopBuffer; int vopBufferLen = Profile()->m_videoMaxVopSize; for (int ix = 0; ix < nal_num; ix++) { int i_size; i_size = x264_nal_encode(vopBuffer, &vopBufferLen, 1, &nal[ix]); if (i_size > 0) { bool useit = false; uint header_size = 0; if (h264_is_start_code(vopBuffer)) { header_size = vopBuffer[2] == 1 ? 3 : 4; } if (nal[ix].i_type == H264_NAL_TYPE_SEQ_PARAM) { found_seq = true; seqlen = i_size - header_size; seqptr = vopBuffer + header_size; useit = true; } else if (nal[ix].i_type == H264_NAL_TYPE_PIC_PARAM) { found_pic = true; piclen = i_size - header_size; picptr = vopBuffer + header_size; useit = true; } if (useit) { vopBuffer += i_size; vopBufferLen -= i_size; } } } if (found_seq == false) { error_message("Can't find seq pointer in x264 header"); StopEncoder(); return false; } if (found_pic == false) { error_message("Can't find pic pointer in x264 header"); StopEncoder(); return false; } uint8_t *p = seqptr; if (*p == 0 && p[1] == 0 && (p[2] == 1 || (p[2] == 0 && p[3] == 1))) { if (p[2] == 0) p += 4; else p += 3; } Profile()->m_videoMpeg4ProfileId = p[1] << 16 | p[2] << 8 | p[3]; debug_message("profile id %x", Profile()->m_videoMpeg4ProfileId); char *sprop = NULL; char *base64; base64 = MP4BinaryToBase64(seqptr, seqlen); sprop = strdup(base64); free(base64); base64 = MP4BinaryToBase64(picptr, piclen); sprop = (char *)realloc(sprop, strlen(sprop) + strlen(base64) + 1 + 1); strcat(sprop, ","); strcat(sprop, base64); free(base64); debug_message("sprop %s", sprop); Profile()->m_videoMpeg4Config = (uint8_t *)sprop; Profile()->m_videoMpeg4ConfigLength = strlen(sprop) + 1; StopEncoder(); return true; }
bool CX264VideoEncoder::EncodeImage( const u_int8_t* pY, const u_int8_t* pU, const u_int8_t* pV, u_int32_t yStride, u_int32_t uvStride, bool wantKeyFrame, Duration elapsedDuration, Timestamp srcFrameTimestamp) { //debug_message("encoding at "U64, srcFrameTimestamp); m_push->Push(srcFrameTimestamp); if (m_vopBuffer == NULL) { m_vopBuffer = (u_int8_t*)malloc(Profile()->m_videoMaxVopSize); if (m_vopBuffer == NULL) { error_message("Cannot malloc vop size"); return false; } } m_count++; if (m_count >= m_key_frame_count) { wantKeyFrame = true; m_count = 0; } #ifdef USE_OUR_YUV m_pic_input.img.plane[0] = (uint8_t *)pY; m_pic_input.img.i_stride[0] = yStride; m_pic_input.img.plane[1] = (uint8_t *)pU; m_pic_input.img.i_stride[1] = uvStride; m_pic_input.img.plane[2] = (uint8_t *)pV; m_pic_input.img.i_stride[2] = uvStride; #else CopyYuv(pY, pU, pV, yStride, uvStride, uvStride, m_pic_input.img.plane[0],m_pic_input.img.plane[1],m_pic_input.img.plane[2], m_pic_input.img.i_stride[0],m_pic_input.img.i_stride[1],m_pic_input.img.i_stride[2], Profile()->m_videoWidth, Profile()->m_videoHeight); #endif m_pic_input.i_type = wantKeyFrame ? X264_TYPE_IDR : X264_TYPE_AUTO; m_pic_input.i_pts = srcFrameTimestamp; x264_nal_t *nal; int i_nal; if (x264_encoder_encode(m_h, &nal, &i_nal, &m_pic_input, &m_pic_output) < 0) { error_message("x264_encoder_encode failed"); return false; } CHECK_AND_FREE(m_nal_info); m_nal_info = (h264_nal_buf_t *)malloc(i_nal * sizeof(h264_nal_buf_t)); uint8_t *vopBuffer = m_vopBuffer; int vopBufferLen = m_vopBufferLength; uint32_t loaded = 0; uint32_t nal_on = 0; // read the nals out of the encoder. Nice... for (int ix = 0; ix < i_nal; ix++) { int i_size; bool skip = false; i_size = x264_nal_encode(vopBuffer, &vopBufferLen, 1, &nal[ix]); if (i_size > 0) { m_nal_info[nal_on].nal_length = i_size; m_nal_info[nal_on].nal_offset = loaded; m_nal_info[nal_on].nal_type = nal[ix].i_type; m_nal_info[nal_on].unique = false; uint32_t header = 0; if (h264_is_start_code(vopBuffer)) { header = vopBuffer[2] == 1 ? 3 : 4; } m_nal_info[nal_on].nal_length -= header; m_nal_info[nal_on].nal_offset += header; // we will send picture or sequence header through - let the // sinks decide to send or not if (skip == false) { #ifdef DEBUG_H264 uint8_t nal_type = nal[ix].i_type; if (h264_nal_unit_type_is_slice(nal_type)) { uint8_t stype; h264_find_slice_type(vopBuffer, i_size, &stype, true); debug_message("nal %d - type %u slice type %u %d", ix, nal_type, stype, i_size); } else { debug_message("nal %d - type %u %d", ix, nal_type, i_size); } #endif nal_on++; loaded += i_size; vopBufferLen -= i_size; vopBuffer += i_size; } else { #ifdef DEBUG_H264 debug_message("skipped nal %u", nal[ix].i_type); #endif } } else { error_message("Need to increase vop buffer size by %d", -i_size); } } m_nal_num = nal_on; m_vopBufferLength = loaded; #ifdef DEBUG_H264 debug_message("x264 loaded %d nals, %u len", i_nal, loaded); #endif #ifdef OUTPUT_RAW if (m_vopBufferLength) { fwrite(m_vopBuffer, m_vopBufferLength, 1, m_outfile); } #endif return true; }