









在广播电视行业,经常需要推送不同的节目流,或者从ts视频流中选择不同的节目流播放,使用ffmpeg来处理还是非常方便的,第一步就是从媒体流信息中取出有多少个节目program,然后每个节目都有多个音视频轨道,切记这里是多个,因为可能一个视频对应多个音轨,有中英双语之类的情况。当然一般默认情况下切换节目都是按照默认的首个轨道来切换,如果还有特殊情况,那就手动指定视音频轨道来设置。一般来说核心底层都是提供了切换视音频轨道的接口,但是用户希望的是直接选择节目编号或者名称进行切换,这样更直接,比我我要看哪个台,我不需要知道这个台的视音频轨道,我只需要告诉程序我要切换到这个台就好,程序底层是自动找到这个台对应的视音频轨道索引,进行设置,就表示切换到这个台了。
最开始做这个功能的时候,还以为切换节目需要重新打开,其实不是的,打开一个ts媒体地址后,对应的流数据就包含了多个节目多个视音频,你只需要跳过不需要看的就行,比如不是当前节目的视音频的索引的数据,直接丢弃不解码就好。推流也是,当前正在解码哪个节目,只需要将正在解码的放入推流队列数据即可,这样推的就是当前播放的节目。

#include "frmmain.h"
#include "ui_frmmain.h"
#include "qthelper.h"
#include "videoutil.h"
#include "videohelper.h"
#include "videothread.h"
#include "widgethelper.h"
#include "bannerwidget.h"
frmMain::frmMain(QWidget *parent) : QWidget(parent), ui(new Ui::frmMain)
{
ui->setupUi(this);
this->initForm();
this->initUrl();
this->initConfig();
}
frmMain::~frmMain()
{
delete ui;
}
void frmMain::initForm()
{
VideoThread::debugInfo = 0;
ui->frame->setFixedWidth(AppData::RightWidth);
ui->sliderPosition->setRange(0, 0);
ui->videoWidget->getBannerWidget()->setProperty("nohide", true);
#if 0
ui->labVideoTrack->setVisible(false);
ui->cboxVideoTrack->setVisible(false);
ui->labAudioTrack->setVisible(false);
ui->cboxAudioTrack->setVisible(false);
ui->btnSetTrack->setVisible(false);
#endif
}
void frmMain::initUrl()
{
VideoUtil::loadMediaUrls(ui->cboxMediaUrl, "", AppConfig::MediaUrl);
}
void frmMain::initConfig()
{
VideoUtil::loadMediaUrl(ui->cboxMediaUrl, AppConfig::MediaUrl, -1);
connect(ui->cboxMediaUrl->lineEdit(), SIGNAL(textChanged(QString)), this, SLOT(saveConfig()));
QStringList ips = QStringList() << QtHelper::getLocalIPs() << "127.0.0.1";
QString host = ips.first();
VideoUtil::loadSaveUrl(ui->cboxSaveUrl, host);
ui->cboxSaveUrl->lineEdit()->setText(AppConfig::SaveUrl);
connect(ui->cboxSaveUrl->lineEdit(), SIGNAL(textChanged(QString)), this, SLOT(saveConfig()));
VideoUtil::loadVideoCore(ui->cboxVideoCore, AppConfig::VideoCore);
connect(ui->cboxVideoCore, SIGNAL(currentIndexChanged(int)), this, SLOT(saveConfig()));
VideoUtil::loadScaleMode(ui->cboxScaleMode);
ui->cboxScaleMode->setCurrentIndex(AppConfig::ScaleMode);
connect(ui->cboxScaleMode, SIGNAL(currentIndexChanged(int)), this, SLOT(saveConfig()));
VideoUtil::loadVideoMode(ui->cboxVideoMode);
ui->cboxVideoMode->setCurrentIndex(AppConfig::VideoMode);
connect(ui->cboxVideoMode, SIGNAL(currentIndexChanged(int)), this, SLOT(saveConfig()));
VideoUtil::loadDecodeType(ui->cboxDecodeType);
ui->cboxDecodeType->setCurrentIndex(AppConfig::DecodeType);
connect(ui->cboxDecodeType, SIGNAL(currentIndexChanged(int)), this, SLOT(saveConfig()));
VideoUtil::loadHardware(ui->cboxHardware, AppConfig::VideoCore, AppConfig::Hardware);
connect(ui->cboxHardware, SIGNAL(currentIndexChanged(int)), this, SLOT(saveConfig()));
}
void frmMain::saveConfig()
{
//内核变化后做出对应的处理/比如切换硬解码名称
int videoCore = ui->cboxVideoCore->itemData(ui->cboxVideoCore->currentIndex()).toInt();
if (AppConfig::VideoCore != videoCore) {
AppConfig::VideoCore = videoCore;
VideoUtil::loadHardware(ui->cboxHardware, videoCore, AppConfig::Hardware);
}
AppConfig::MediaUrl = ui->cboxMediaUrl->currentText().trimmed();
AppConfig::SaveUrl = ui->cboxSaveUrl->currentText().trimmed();
AppConfig::ScaleMode = ui->cboxScaleMode->currentIndex();
AppConfig::VideoMode = ui->cboxVideoMode->currentIndex();
AppConfig::DecodeType = ui->cboxDecodeType->currentIndex();
AppConfig::Hardware = ui->cboxHardware->currentText();
AppConfig::writeConfig();
}
void frmMain::initPara()
{
VideoHelper::initVideoWidget(ui->videoWidget, AppConfig::MediaUrl, AppConfig::VideoCore, AppConfig::ScaleMode, AppConfig::VideoMode, AppConfig::Hardware, "");
//加点其他参数
VideoPara videoPara = ui->videoWidget->getVideoPara();
videoPara.decodeType = (DecodeType)AppConfig::DecodeType;
videoPara.readTimeout = 60 * 1000;
ui->videoWidget->setVideoPara(videoPara);
}
void frmMain::receivePlayStart(int time)
{
ui->videoWidget->recordStart(AppConfig::SaveUrl);
}
void frmMain::receivePlayFinsh()
{
VideoUtil::resetDuration(ui->labDuration, ui->labPosition, ui->sliderPosition);
}
void frmMain::receiveDuration(qint64 duration)
{
VideoUtil::setDuration(ui->labDuration, ui->sliderPosition, duration);
}
void frmMain::receivePosition(qint64 position)
{
VideoUtil::setPosition(ui->labPosition, ui->sliderPosition, position);
}
void frmMain::receiveProgram(const QList<ProgramInfo> &programs)
{
int count = programs.count();
if (count == 0) {
return;
}
ui->cboxProgram->blockSignals(true);
ui->cboxProgram->clear();
//将所有节目信息添加到下拉框
this->programs = programs;
foreach (ProgramInfo program, programs) {
ui->cboxProgram->addItem(program.name);
}
//获取当前正在播放的节目
VideoThread *videoThread = ui->videoWidget->getVideoThread();
int programId = videoThread->getProgramId();
int audioTrack = videoThread->getAudioTrack();
int videoTrack = videoThread->getVideoTrack();
//设置当前正在播放的节目对应的下拉框
on_cboxProgram_currentIndexChanged(programId);
ui->cboxProgram->setCurrentIndex(programId);
int audioIndex = ui->cboxAudioTrack->findText(QString::number(audioTrack));
int videoIndex = ui->cboxVideoTrack->findText(QString::number(videoTrack));
ui->cboxAudioTrack->setCurrentIndex(audioIndex >= 0 ? audioIndex : 0);
ui->cboxVideoTrack->setCurrentIndex(videoIndex >= 0 ? videoIndex : 0);
ui->cboxProgram->blockSignals(false);
}
void frmMain::on_cboxProgram_currentIndexChanged(int index)
{
ui->cboxAudioTrack->clear();
ui->cboxVideoTrack->clear();
if (index < 0) {
return;
}
ProgramInfo program = programs.at(index);
QList<int> audioTracks = program.audioTracks;
foreach (int track, audioTracks) {
ui->cboxAudioTrack->addItem(QString::number(track));
}
QList<int> videoTracks = program.videoTracks;
foreach (int track, videoTracks) {
ui->cboxVideoTrack->addItem(QString::number(track));
}
//节目下拉框产生的动作立即执行切换
if (sender() == ui->cboxProgram) {
on_btnSetTrack_clicked();
}
}
void frmMain::on_btnPlay_clicked()
{
//初始化参数
this->initPara();
if (!ui->videoWidget->init()) {
return;
}
//关联采集线程信号槽
VideoThread *videoThread = ui->videoWidget->getVideoThread();
//videoThread->setDecodeType(DecodeType_Full);
connect(videoThread, SIGNAL(receivePlayStart(int)), this, SLOT(receivePlayStart(int)));
connect(videoThread, SIGNAL(receivePlayFinsh()), this, SLOT(receivePlayFinsh()));
connect(videoThread, SIGNAL(receiveDuration(qint64)), this, SLOT(receiveDuration(qint64)));
connect(videoThread, SIGNAL(receivePosition(qint64)), this, SLOT(receivePosition(qint64)));
connect(videoThread, SIGNAL(receiveProgram(QList<ProgramInfo>)), this, SLOT(receiveProgram(QList<ProgramInfo>)));
//设置默认视音频轨道
//videoThread->setProgram(1);
//videoThread->setAudioTrack(5);
//videoThread->setVideoTrack(4);
//开始播放
ui->videoWidget->play();
}
void frmMain::on_btnStop_clicked()
{
programs.clear();
ui->cboxProgram->clear();
ui->videoWidget->stop();
}
void frmMain::on_btnSetTrack_clicked()
{
//可以指定节目/也可以选择指定具体的轨道/两种都支持/非常的万能
if (ui->videoWidget->getIsRunning()) {
#if 1
int programId = ui->cboxProgram->currentIndex();
ui->videoWidget->getVideoThread()->setProgram(programId);
#else
int audioTrack = ui->cboxAudioTrack->currentText().toInt();
int videoTrack = ui->cboxVideoTrack->currentText().toInt();
ui->videoWidget->getVideoThread()->setTrack(audioTrack, videoTrack);
#endif
}
}
void frmMain::on_sliderPosition_clicked()
{
int value = ui->sliderPosition->value();
on_sliderPosition_sliderMoved(value);
}
void frmMain::on_sliderPosition_sliderMoved(int value)
{
ui->videoWidget->setPosition(value);
}
void frmMain::on_ckPause_stateChanged(int arg1)
{
if (arg1 != 0) {
ui->videoWidget->pause();
} else {
ui->videoWidget->next();
}
}
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。