float BleX264Encoder::getFrameDuration() { MOption *option = MOption::instance(); int fps = option->option("fps", "encoder").toInt(); if (fps > 0) { return 1000.0000 / (float)fps; } // 40 ms : default duration return 40.0f; }
int BleX264Encoder::init() { MOption *option = MOption::instance(); QString presetName = option->option("preset", "x264").toString(); QString tuneName = option->option("tune", "x264").toString(); QString profileName = option->option("profile", "x264").toString(); int fps = option->option("fps", "encoder").toInt(); int kbps = option->option("bitrate", "encoder").toInt(); QSize wh = option->option("res", "encoder").toSize(); int width = wh.width(); int height = wh.height(); int maxBitRate = kbps; int bufferSize = maxBitRate; bool bUseCBR = (option->option("BitrateMode", "x264").toString() == "CBR"); int quality = option->option("quality", "x264").toInt(); int KeyFrameInterval = option->option("KeyFrameInterval", "x264").toInt(); int threadCount = option->option(Key_Thread_Count, Group_X264).toInt(); bool enableBFrame = option->option(Key_Enable_B_Frame, Group_X264).toString() == "true" ? true : false; int B_frame_count = option->option(Key_B_Frame_Count, Group_X264).toInt(); m_x264Param = new x264_param_t; if (tuneName == "Default" || tuneName.isEmpty()) { x264_param_default_preset(m_x264Param , presetName.toStdString().c_str(), NULL); log_trace("libx264 preset set to %s, tune set to NULL" , presetName.toStdString().c_str()); } else { x264_param_default_preset(m_x264Param , presetName.toStdString().c_str(), tuneName.toStdString().c_str()); log_trace("libx264 preset set to %s, tune set to %s"\ , presetName.toStdString().c_str(), tuneName.toStdString().c_str()); } if (profileName != "Default") { x264_param_apply_profile(m_x264Param, profileName.toStdString().c_str()); log_trace("libx264 profile set to %s", profileName.toStdString().c_str()); } else { log_trace("libx264 profile set to Default"); } if(bUseCBR) { m_x264Param->rc.i_bitrate = maxBitRate; m_x264Param->rc.i_vbv_max_bitrate = maxBitRate; // vbv-maxrate m_x264Param->rc.i_vbv_buffer_size = bufferSize; // vbv-bufsize m_x264Param->i_nal_hrd = X264_NAL_HRD_CBR; m_x264Param->rc.i_rc_method = X264_RC_ABR; m_x264Param->rc.f_rf_constant = 0.0f; } else { m_x264Param->rc.i_vbv_max_bitrate = maxBitRate; // vbv-maxrate m_x264Param->rc.i_vbv_buffer_size = bufferSize; // vbv-bufsize m_x264Param->rc.i_rc_method = X264_RC_CRF; // X264_RC_CRF; m_x264Param->rc.f_rf_constant = 10.0f + float(20 - quality); log_trace("libx264 quality set to %d", quality); } m_x264Param->b_vfr_input = 1; m_x264Param->i_keyint_max = fps * KeyFrameInterval; m_x264Param->i_width = width; m_x264Param->i_height = height; m_x264Param->vui.b_fullrange = 0; //specify full range input levels // For some codecs, the time base is closer to the field rate than the frame rate. // Most notably, H.264 and MPEG-2 specify time_base as half of frame duration // if no telecine is used ... // Set to time_base ticks per frame. Default 1, e.g., H.264/MPEG-2 set it to 2. // @see ffmpeg: AVodecContex::ticks_per_frame // never use timebase = 1000, because vlc will show 1000 fps !! int ticks_per_frame = 2; m_x264Param->i_timebase_num = 1; m_x264Param->i_timebase_den = fps; m_x264Param->i_fps_num = m_x264Param->i_timebase_den; m_x264Param->i_fps_den = m_x264Param->i_timebase_num * ticks_per_frame; // disable start code 00 00 00 01 before NAL // instead of nalu size m_x264Param->b_repeat_headers = 0; m_x264Param->b_annexb = 0; m_x264Param->i_frame_reference = 5; if (enableBFrame) { m_x264Param->i_bframe = B_frame_count; m_x264Param->i_bframe_bias = 100; m_x264Param->i_bframe_adaptive = 1; if (B_frame_count >= 2) m_x264Param->i_bframe_pyramid = 1; } else m_x264Param->i_bframe = 0; if (threadCount > 0) m_x264Param->i_threads = threadCount; // @note // never use cpu capabilities. // let libx264 to choose. #if 0 m_x264Param->cpu = 0; m_x264Param->cpu |=X264_CPU_MMX; m_x264Param->cpu |=X264_CPU_MMXEXT; m_x264Param->cpu |=X264_CPU_SSE; #endif m_x264Encoder = x264_encoder_open(m_x264Param); // update video sh x264_nal_t *nalOut; int nalNum; x264_encoder_headers(m_x264Encoder, &nalOut, &nalNum); for (int i = 0; i < nalNum; ++i) { x264_nal_t &nal = nalOut[i]; if (nal.i_type == NAL_SPS) { BleVideoPacket *pkt = new BleVideoPacket(Video_Type_H264); pkt->dts = 0; MStream &body = pkt->data; // SPS Serialize body.write1Bytes(0x17); body.write1Bytes(0x00); body.write3Bytes(0x00); body.write1Bytes(0x01); body.writeString((char*)nal.p_payload + 5, 3); body.write1Bytes(0xff); body.write1Bytes(0xe1); body.write2Bytes(nal.i_payload - 4); body.writeString((char*)nal.p_payload + 4, nal.i_payload - 4); //the PPS always comes after the SPS x264_nal_t &pps = nalOut[++i]; // PPS Serialize body.write1Bytes(0x01); body.write2Bytes(pps.i_payload - 4); body.writeString(MString((char*)pps.p_payload + 4, pps.i_payload - 4)); appCtx->setVideoSh(pkt); } else if (nal.i_type == NAL_SEI) { BleVideoPacket *seiPkt = new BleVideoPacket(Video_Type_H264); seiPkt->dts = 0; seiPkt->has_encoded = true; MStream &seiBody = seiPkt->data; int skipBytes = 4; int newPayloadSize = (nal.i_payload - skipBytes); unsigned char flshFrameType = 0x17; seiBody.write1Bytes(flshFrameType); seiBody.write1Bytes(0x01); seiBody.write3Bytes(0x00); seiBody.write4Bytes(newPayloadSize); seiBody.writeString((char*)nal.p_payload + skipBytes, newPayloadSize); BleAVQueue::instance()->enqueue(seiPkt); } } m_pictureIn = new x264_picture_t; m_pictureIn->i_pts = 0; return BLE_SUCESS; }
void BleSetting::restore() { MOption *option = MOption::instance(); // audio group int audioDevID = option->option("dev_id", "audio").toInt(); QString audioFormat = option->option("format", "audio").toString(); QString audioChannels = option->option("channels", "audio").toString(); QString audioSampleRate = option->option("sample_rate", "audio").toString(); QString audioBitrate = option->option("sample_rate", "audio").toString(); // find dev ID int audioDevCount = ui->audioDevice->count(); for (int i = 0; i < audioDevCount; ++i) { if (ui->audioDevice->itemData(i).toInt() == audioDevID) { ui->audioDevice->setCurrentIndex(i); break; } } setIndex(ui->audioFormat, audioFormat); setIndex(ui->audioChannels, audioChannels); setIndex(ui->audioSampleRate, audioSampleRate); setIndex(ui->audioBitrate, audioBitrate); // encoder group QString format = option->option("format", "encoder").toString(); QVariant res = option->option("res", "encoder"); QString fps = option->option("fps", "encoder").toString(); QString bitrate = option->option("bitrate", "encoder").toString(); setIndex(ui->format, format); ui->res->setCurrentIndex(ui->res->findData(res)); setIndex(ui->fps, fps); setIndex(ui->bitrate, bitrate); // x264 group QString x264Preset = option->option("preset", "x264").toString(); QString x264Tune = option->option("tune", "x264").toString(); QString x264Profile = option->option("profile", "x264").toString(); QString bitrateMode = option->option("BitrateMode", "x264").toString(); QString keyFrameInterval = option->option("KeyFrameInterval", "x264").toString(); QString threadCount = option->option(Key_Thread_Count, Group_X264).toString(); QString enableBFrame = option->option(Key_Enable_B_Frame, Group_X264).toString(); QString quality = option->option("quality", "x264").toString(); setIndex(ui->x264Preset, x264Preset); setIndex(ui->x264Tune, x264Tune); setIndex(ui->x264Profile, x264Profile); setIndex(ui->bitrateMode, bitrateMode); setIndex(ui->keyFrameInterval, keyFrameInterval); setIndex(ui->threadCount, threadCount); ui->enableBFrame->setChecked((enableBFrame == "true") ? true: false); ui->qualityBar->setValue(quality.toInt()); // network group QString address = option->option("address", "network").toString(); ui->address->setText(address); }