各大电视台的rtmp/hls视频源


CCTV-1综合:rtmp://58.200.131.2:1935/livetv/cctv1
CCTV-2财经:rtmp://58.200.131.2:1935/livetv/cctv2
CCTV-3综艺:rtmp://58.200.131.2:1935/livetv/cctv3
CCTV-4中文国际:rtmp://58.200.131.2:1935/livetv/cctv4
CCTV-5体育:rtmp://58.200.131.2:1935/livetv/cctv5
CCTV-6电影:rtmp://58.200.131.2:1935/livetv/cctv6
CCTV-7军事农业:rtmp://58.200.131.2:1935/livetv/cctv7
CCTV-8电视剧:rtmp://58.200.131.2:1935/livetv/cctv8
CCTV-9记录:rtmp://58.200.131.2:1935/livetv/cctv9
CCTV-10科教:rtmp://58.200.131.2:1935/livetv/cctv10
CCTV-11戏曲:rtmp://58.200.131.2:1935/livetv/cctv11
CCTV-12社会与法:rtmp://58.200.131.2:1935/livetv/cctv12
CCTV-13新闻:rtmp://58.200.131.2:1935/livetv/cctv13
CCTV-14少儿:rtmp://58.200.131.2:1935/livetv/cctv14
CCTV-15音乐:rtmp://58.200.131.2:1935/livetv/cctv15
安徽卫视:rtmp://58.200.131.2:1935/livetv/ahtv
兵团卫视:rtmp://58.200.131.2:1935/livetv/bttv
重庆卫视:rtmp://58.200.131.2:1935/livetv/cqtv
东方卫视:rtmp://58.200.131.2:1935/livetv/dftv
东南卫视:rtmp://58.200.131.2:1935/livetv/dntv
广东卫视:rtmp://58.200.131.2:1935/livetv/gdtv
广西卫视:rtmp://58.200.131.2:1935/livetv/gxtv
甘肃卫视:rtmp://58.200.131.2:1935/livetv/gstv
贵州卫视:rtmp://58.200.131.2:1935/livetv/gztv
湖北卫视:rtmp://58.200.131.2:1935/livetv/hbtv
湖南卫视:rtmp://58.200.131.2:1935/livetv/hunantv
河北卫视:rtmp://58.200.131.2:1935/livetv/hebtv
河南卫视:rtmp://58.200.131.2:1935/livetv/hntv
黑龙江卫视:rtmp://58.200.131.2:1935/livetv/hljtv
江苏卫视:rtmp://58.200.131.2:1935/livetv/jstv
江西卫视:rtmp://58.200.131.2:1935/livetv/jxtv
吉林卫视:rtmp://58.200.131.2:1935/livetv/jltv
辽宁卫视:rtmp://58.200.131.2:1935/livetv/lntv
内蒙古卫视:rtmp://58.200.131.2:1935/livetv/nmtv
宁夏卫视:rtmp://58.200.131.2:1935/livetv/nxtv
青海卫视:rtmp://58.200.131.2:1935/livetv/qhtv
四川卫视:rtmp://58.200.131.2:1935/livetv/sctv
山东卫视:rtmp://58.200.131.2:1935/livetv/sdtv
山西卫视:rtmp://58.200.131.2:1935/livetv/sxrtv
陕西卫视:rtmp://58.200.131.2:1935/livetv/sxtv
山东教育:rtmp://58.200.131.2:1935/livetv/sdetv
中国教育-1:rtmp://58.200.131.2:1935/livetv/cetv1
中国教育-3:rtmp://58.200.131.2:1935/livetv/cetv3
中国教育-4:rtmp://58.200.131.2:1935/livetv/cetv4
CCTV-第一剧场:rtmp://58.200.131.2:1935/livetv/dyjctv
CCTV-国防军事:rtmp://58.200.131.2:1935/livetv/gfjstv
CCTV-怀旧剧场:rtmp://58.200.131.2:1935/livetv/hjjctv
CCTV-风云剧场:rtmp://58.200.131.2:1935/livetv/fyjctv
CCTV-风云足球:rtmp://58.200.131.2:1935/livetv/fyzqtv
CCTV-风云音乐:rtmp://58.200.131.2:1935/livetv/fyyytv
CCTV-世界地理:rtmp://58.200.131.2:1935/livetv/sjdltv
CCTV-1HD:rtmp://58.200.131.2:1935/livetv/cctv1hd
CCTV-2HD:rtmp://58.200.131.2:1935/livetv/cctv2hd
CCTV-3HD:rtmp://58.200.131.2:1935/livetv/cctv3hd
CCTV-4HD:rtmp://58.200.131.2:1935/livetv/cctv4hd
CCTV-5HD:rtmp://58.200.131.2:1935/livetv/cctv5hd
CCTV5+HD:rtmp://58.200.131.2:1935/livetv/cctv5phd
CCTV-6HD:rtmp://58.200.131.2:1935/livetv/cctv6hd
CCTV-7HD:rtmp://58.200.131.2:1935/livetv/cctv7hd
CCTV-8HD:rtmp://58.200.131.2:1935/livetv/cctv8hd
CCTV-9HD:rtmp://58.200.131.2:1935/livetv/cctv9hd
CCTV-10HD:rtmp://58.200.131.2:1935/livetv/cctv10hd
CCTV-12HD:rtmp://58.200.131.2:1935/livetv/cctv12hd
CCTV-14HD:rtmp://58.200.131.2:1935/livetv/cctv14hd
CGTN-新闻:rtmp://58.200.131.2:1935/livetv/cctv16
CETV-1:rtmp://58.200.131.2:1935/livetv/cetv1
CETV-3:rtmp://58.200.131.2:1935/livetv/cetv3
CETV-4:rtmp://58.200.131.2:1935/livetv/cetv4
北京卫视高清:rtmp://58.200.131.2:1935/livetv/btv1hd
北京影视高清:rtmp://58.200.131.2:1935/livetv/btv4hd
北京体育高清:rtmp://58.200.131.2:1935/livetv/btv6hd
北京新闻高清:rtmp://58.200.131.2:1935/livetv/btv9hd
北京纪实高清:rtmp://58.200.131.2:1935/livetv/btv11hd
北京卫视:rtmp://58.200.131.2:1935/livetv/btv1
北京文艺:rtmp://58.200.131.2:1935/livetv/btv2
北京科教:rtmp://58.200.131.2:1935/livetv/btv3
北京影视:rtmp://58.200.131.2:1935/livetv/btv4
北京财经:rtmp://58.200.131.2:1935/livetv/btv5
北京体育:rtmp://58.200.131.2:1935/livetv/btv6
北京生活:rtmp://58.200.131.2:1935/livetv/btv7
北京青年:rtmp://58.200.131.2:1935/livetv/btv8
北京新闻:rtmp://58.200.131.2:1935/livetv/btv9
北京卡酷:rtmp://58.200.131.2:1935/livetv/btv10
北京文艺高清:rtmp://58.200.131.2:1935/livetv/btv2hd
安徽卫视高清:rtmp://58.200.131.2:1935/livetv/ahhd
重庆卫视高清:rtmp://58.200.131.2:1935/livetv/cqhd
东方卫视高清:rtmp://58.200.131.2:1935/livetv/dfhd
天津卫视高清:rtmp://58.200.131.2:1935/livetv/tjhd
东南卫视高清:rtmp://58.200.131.2:1935/livetv/dnhd
江西卫视高清:rtmp://58.200.131.2:1935/livetv/jxhd
河北卫视高清:rtmp://58.200.131.2:1935/livetv/hebhd
湖南卫视高清:rtmp://58.200.131.2:1935/livetv/hunanhd
湖北卫视高清:rtmp://58.200.131.2:1935/livetv/hbhd
辽宁卫视高清:rtmp://58.200.131.2:1935/livetv/lnhd
四川卫视高清:rtmp://58.200.131.2:1935/livetv/schd
江苏卫视高清:rtmp://58.200.131.2:1935/livetv/jshd
浙江卫视高清:rtmp://58.200.131.2:1935/livetv/zjhd
山东卫视高清:rtmp://58.200.131.2:1935/livetv/sdhd
广东卫视高清:rtmp://58.200.131.2:1935/livetv/gdhd
深圳卫视高清:rtmp://58.200.131.2:1935/livetv/szhd
黑龙江卫视高清:rtmp://58.200.131.2:1935/livetv/hljhd
CHC高清电影:rtmp://58.200.131.2:1935/livetv/chchd
上海纪实高清:rtmp://58.200.131.2:1935/livetv/docuchina
金鹰纪实高清:rtmp://58.200.131.2:1935/livetv/gedocu
全纪实高清:rtmp://58.200.131.2:1935/livetv/documentaryhd
凤凰卫视中文台:rtmp://58.200.131.2:1935/livetv/fhzw
凤凰卫视资讯台:rtmp://58.200.131.2:1935/livetv/fhzx
凤凰卫视电影台:rtmp://58.200.131.2:1935/livetv/fhdy
星空卫视:rtmp://58.200.131.2:1935/livetv/startv
Star Sports:rtmp://58.200.131.2:1935/livetv/starsports
Channel[V]:rtmp://58.200.131.2:1935/livetv/channelv
探索频道:rtmp://58.200.131.2:1935/livetv/discovery
国家地理频道:rtmp://58.200.131.2:1935/livetv/natlgeo
CHC家庭影院:rtmp://58.200.131.2:1935/livetv/chctv
CHC动作电影:rtmp://58.200.131.2:1935/livetv/chcatv
美国电视频道:rtmp://media3.scctv.net/live/scctv_800
香港财经:rtmp://202.69.69.180:443/webcast/bshdlive-pc


CCTV-1综合.m3u8
http://223.110.242.130:6610/gitv/live1/G_CCTV-1-HQ/1.m3u8
CCTV-2财经.m3u8
http://112.50.243.10/PLTV/88888888/224/3221225800/1.m3u8
CCTV-3综艺.m3u8
http://183.207.249.14/PLTV/3/224/3221225588/index.m3u8
CCTV-4中文国际.m3u8
http://223.110.242.130:6610/gitv/live1/G_CCTV-4-HQ/1.m3u8
CCTV-5体育.m3u8
http://223.110.243.172/PLTV/3/224/3221227166/index.m3u8
CCTV-5+体育赛事.m3u8
http://223.110.243.162/PLTV/3/224/3221225604/index.m3u8
CCTV-6电影.m3u8
http://223.110.243.139/PLTV/3/224/3221225548/index.m3u8
CCTV-7军事农业.m3u8
http://112.50.243.8/PLTV/88888888/224/3221225805/1.m3u8
CCTV-8电视剧.m3u8
http://223.110.243.171/PLTV/3/224/3221227204/index.m3u8
CCTV-9记录.m3u8
http://112.50.243.8/PLTV/88888888/224/3221225820/1.m3u8
CCTV-10科教.m3u8
http://183.207.249.14/PLTV/3/224/3221225550/index.m3u8
CCTV-11戏曲.m3u8
http://112.50.243.8/PLTV/88888888/224/3221225815/1.m3u8
CCTV-12社会与法.m3u8
http://223.110.245.172/PLTV/3/224/3221225556/index.m3u8
CCTV-13新闻.m3u8
http://112.50.243.8/PLTV/88888888/224/3221225817/1.m3u8
CCTV-14少儿.m3u8
http://223.110.245.169/PLTV/3/224/3221227201/index.m3u8
CCTV-15音乐.m3u8
http://112.50.243.8/PLTV/88888888/224/3221225818/1.m3u8
湖南卫视高清.m3u8
http://112.50.243.8/PLTV/88888888/224/3221225827/1.m3u8
江苏卫视高清.m3u8
http://112.50.243.8/PLTV/88888888/224/3221225847/1.m3u8
浙江卫视高清.m3u8
http://223.110.243.153/PLTV/3/224/3221227215/index.m3u8
东方卫视高清.m3u8
http://112.50.243.8/PLTV/88888888/224/3221225828/1.m3u8
北京卫视高清.m3u8
http://112.50.243.8/PLTV/88888888/224/3221225826/1.m3u8
广东卫视高清.m3u8
http://112.50.243.8/PLTV/88888888/224/3221225824/1.m3u8
深圳卫视高清.m3u8
http://112.50.243.8/PLTV/88888888/224/3221225848/1.m3u8
天津卫视高清.m3u8
http://112.50.243.8/PLTV/88888888/224/3221225830/1.m3u8
安徽卫视高清.m3u8
http://223.110.243.140/PLTV/3/224/3221225634/index.m3u8
山东卫视高清.m3u8
http://112.50.243.8/PLTV/88888888/224/3221225843/1.m3u8
湖北卫视高清.m3u8
http://223.110。243.140/PLTV/3/224/3221227211/index.m3u8
辽宁卫视高清.m3u8
http://223.110.243.157/PLTV/3/224/3221225566/index.m3u8
重庆卫视高清.m3u8
http://223.110.243.138/PLTV/3/224/3221227421/index.m3u8
江西卫视高清.m3u8
http://112.50.243.8/PLTV/88888888/224/3221225868/1.m3u8
河北卫视高清.m3u8
http://weblive.hebtv.com/live/hbws_bq/index.m3u8
黑龙江卫视高清.m3u8
http://112.50.243.8/PLTV/88888888/224/3221225862/1.m3u8
四川卫视.m3u8
http://ott.js.chinamobile.com/PLTV/3/224/3221225814/index.m3u8
广西卫视.m3u8
http://223.110.243.162/PLTV/3/224/3221225554/index.m3u8
河南卫视.m3u8
http://112.50.243.8/PLTV/88888888/224/3221225842/1.m3u8
山西卫视.m3u8
http://112.50.243.8/PLTV/88888888/224/3221225839/1.m3u8
东南卫视.m3u8
http://223.110.243.158/PLTV/3/224/3221225598/index.m3u8
厦门卫视.m3u8
http://ott.js.chinamobile.com/PLTV/3/224/3221226093/index.m3u8
云南卫视.m3u8
http://112.50.243.8/PLTV/88888888/224/3221225853/1.m3u8
宁夏卫视.m3u8
http://223.110.243.166/PLTV/3/224/3221225628/1.m3u8
新疆卫视.m3u8
http://223.110.243.140/PLTV/3/224/3221225523/index.m3u8
旅游卫视.m3u8
http://112.50.243.8/PLTV/88888888/224/3221225855/1.m3u8
内蒙古卫视.m3u8
http://223.110.243.142/PLTV/3/224/3221225624/index.m3u8
凤凰中文台超清.m3u8
http://223.110.243.146/PLTV/3/224/3221226922/index.m3u8
凤凰资讯台超清.m3u8
http://223.110.243.146/PLTV/3/224/3221226923/index.m3u8
凤凰香港台超清.m3u8
http://223.110.243.146/PLTV/3/224/3221226975/index.m3u8
Newtv动作电影.m3u8
http://183.207.249.15/PLTV/3/224/3221225529/index.m3u8
Newtv惊悚悬疑.m3u8
http://183.207.249.7/PLTV/3/224/3221225561/index.m3u8
Newtv精品电影.m3u8
http://183.207.249.14/PLTV/3/224/3221225567/index.m3u8
Newtv明星大片.m3u8
http://183.207.249.14/PLTV/3/224/3221225535/index.m3u8
Newtv家庭剧场.m3u8
http://183.207.249.14/PLTV/3/224/3221225549/index.m3u8
Newtv精品大剧.m3u8
http://183.207.249.14/PLTV/3/224/3221225569/index.m3u8
Newtv金牌综艺.m3u8
http://183.207.249.16/PLTV/3/224/3221225559/index.m3u8
Newtv精品记录.m3u8
http://183.207.249.14/PLTV/3/224/3221225557/index.m3u8
Newtv精品体育.m3u8
http://183.207.249.16/PLTV/3/224/3221225543/index.m3u8
Newtv北京纪实.m3u8
http://117.169.79.101:8080/PLTV/88888888/224/3221225764/index.m3u8
Newtv上海纪实.m3u8
http://huaweicdn.hb.chinamobile.com/PLTV/88888888/224/3221225769/3.m3u8
Newtv全纪实.m3u8
http://huaweicdn.hb.chinamobile.com/PLTV/88888888/224/3221225791/3.m3u8
Newtv欢笑剧场.m3u8
http://huaweicdn.hb.chinamobile.com/PLTV/88888888/224/3221225776/3.m3u8
Newtv都市剧场.m3u8
http://huaweicdn.hb.chinamobile.com/PLTV/88888888/224/3221225754/3.m3u8


Newtv纪实天下(电).m3u8
rtsp://120.205.96.36:554/live/ch16022917175374294745.sdp?playtype=1&boid=001&backupagent=120.205.32.36:554&clienttype=1&time=20161205230814+08&life=172800&ifpricereqsnd=1&vcdnid=001&userid=&mediaid=ch16022917175374294745&ctype=2&TSTVTimeLife=60&contname=&authid=0&terminalflag=1&UserLiveType=0&stbid=&nodelevel=3

- 阅读全文 -

QT5开发笔记(25)-- 日志


日志函数:

#include <QtMessageHandler>
#include <qlogging.h>
void MsgLog(QtMsgType type, const QMessageLogContext &msgCxt, const QString &msg)
{
    (void)msgCxt;
    /// 日志文件路径;
    QString log_path = "/media/sda/log/";
    static QMutex mutex;
    mutex.lock();
    QString text;
    switch (type)
    {
    case QtDebugMsg:
        text = QString("[%1] %2 %3").arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss")).arg(QString("Debug:")).arg(msg);
        fprintf(stderr, "%s\n", msg.toStdString().c_str());
        break;
    case QtWarningMsg:
        text = QString("[%1] %2 %3").arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss")).arg(QString("Warning:")).arg(msg);
        fprintf(stderr, "%s\n", msg.toStdString().c_str());
        break;
    case QtCriticalMsg:
        text = QString("[%1] %2 %3").arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss")).arg(QString("Critical:")).arg(msg);
        fprintf(stderr, "%s\n", msg.toStdString().c_str());
        break;
    case QtFatalMsg:
        text = QString("[%1] %2 %3").arg(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss")).arg(QString("Fatal:")).arg(msg);
        fprintf(stderr, "%s\n", msg.toStdString().c_str());
        abort();
        break;
    default:
        break;
    }
    if (!text.isEmpty())
    {
        QString message = text;
        QString log_file = "log_" + QDateTime::currentDateTime().toString("yyyyMMdd") + ".log";
        QFile file(log_path + log_file);
        if (!file.open(QIODevice::WriteOnly | QIODevice::Append))
        {
            fprintf(stderr, "%s\n", file.errorString().toStdString().c_str());
        }
        QTextStream ts(&file);
        ts << message << endl;
        file.flush();
        file.close();
    }
    mutex.unlock();
}

在主函数中注册:

int main(int argc, char *argv[])
{
    // 注册回调消息函数
    qInstallMessageHandler(MsgLog);

    QApplication a(argc, argv);
    MainWindow w;
    w.show();
    return a.exec();
}

在代码中直接调用 qDebug 等函数即可:

qDebug() << "HelloWorld";
qInfo()  << "HelloWorld";

- 阅读全文 -

Python学习笔记--rtmp推流


文章摘要:
本文介绍了通过Python抓取摄像头图像,并进行推流的操作的一种方法,也适用于视频文件或图片转换成视频流。
关键技术:
opencv, ffmpeg, subprocess , popen

import subprocess as sp
import cv2 
rtmpUrl = "rtmp://10.0.9.61/live";

cap = cv2.VideoCapture(0)
#cap = cv2.VideoCapture("/media/pi/Movie/A.Funny.Movie.mp4")
 
# Get video information
fps = int(cap.get(cv2.CAP_PROP_FPS))
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
 
# ffmpeg command
command = ['ffmpeg',
        '-y',
        '-f', 'rawvideo',
        '-vcodec','rawvideo',
        '-pix_fmt', 'bgr24',
        '-s', "{}x{}".format(width, height),
        '-r', str(fps),
        '-i', '-',
        '-c:v', 'libx264',
        '-pix_fmt', 'yuv420p',
        '-preset', 'ultrafast',
        '-f', 'flv', 
        rtmpUrl]
print( command) 
# 管道配置
p = sp.Popen(command, stdin=sp.PIPE)
 
# read webcamera
while(cap.isOpened()):
    ret, frame = cap.read()
    if not ret:
        print("Opening camera is failed")
        break
 
    # process frame
    # your code
    # process frame
 
    # write to pipe
    p.stdin.write(frame.tostring())

- 阅读全文 -

QT5开发笔记(24)-- 图像格式转换


QImage-->Mat (opencv)

Mat img_mat;
img_mat = cv::Mat(image.height(),           // 图像高度
                  image.width(),            // 图像宽度
                  CV_8UC3,                  // 图像格式(输出格式)
                  (void*)image.constBits(), // 原始数据   
                  image.bytesPerLine());    // 每行字节数(输入格式决定)

// BGR格式转换为RGB格式
cv::cvtColor(img_mat, img_mat, CV_BGR2RGB);

Mat-->QImage

QImage image = QImage((const uchar*)frame.data,
                      frame.cols,
                      frame.rows,
                      QImage::Format_RGB888).rgbSwapped();   // 也需要进行颜色转换

QImage-->AVFrame(ffmpeg)

uint8_t *indata[AV_NUM_DATA_POINTERS] = { 0 };    /// AV_NUM_DATA_POINTERS
int insize[AV_NUM_DATA_POINTERS] = { 0 };         /// 在AVFrame中定义,其值为 8

/// ffmpeg编码部分
indata[0] = (uint8_t*)image->constBits();   /// QImage中的数据
insize[0] = image->bytesPerLine();          /// 一行(宽)数据的字节数
int h = sws_scale(pSwsCxt,
                  indata,
                  insize,
                  0,
                  image->height(),          /// 源数据行数
                  pFrame->data,             /// AVFrame数据指针(输出)
                  pFrame->linesize);

AVFrame-->QImage

QImage img = QImage((uchar *)pFrameOut->data,
                    pCodeCtxV->width,
                    pCodeCtxV->height,
                    QImage::Format_RGB888);    // 格式必须与解码器中的定义一致

BayerGB2RGB(海康相机):

   Mat img_mat;
   img_mat = cv::Mat(cameraHeight,             // 图像高度
                     cameraWidth,              // 图像宽度
                     CV_8UC1,                  // 图像格式(输出格式)
                     (void*)mvframe.pBufAddr,  // 原始数据
                     cameraWidth);             // 每行字节数(输入格式决定)
  cvtColor(img_mat, img_mat, COLOR_BayerGB2RGB);
  QImage img2 = QImage((const uchar*)img_mat.data,
                        img_mat.cols,
                        img_mat.rows,
                        QImage::Format_RGB888);

图像格式: 静态图像的数据组织形式,RGB888, RGB32, YUV等
视频格式: 将图像按规则编码成视频流,H264,MPEG2等

https://blog.csdn.net/qq_41498261/article/details/84205505

- 阅读全文 -

QT5开发笔记(23)--ffmpe推流


https://blog.csdn.net/wzz953200463/article/details/115983926

https://blog.csdn.net/leixiaohua1020/article/details/25430449
https://blog.csdn.net/tnb1992/article/details/106544970/
https://www.jianshu.com/p/d3edb368b36c

#include
using namespace std;
//引入头文件
extern "C"
{
#include "libavformat/avformat.h"
//引入时间
#include "libavutil/time.h"
}
//引入库
#pragma comment(lib,"avformat.lib")
//工具库,包括获取错误信息等
#pragma comment(lib,"avutil.lib")
//编解码的库
#pragma comment(lib,"avcodec.lib")

int avError(int errNum);

static double r2d(AVRational r)
{
return r.num == 0 || r.den == 0 ? 0. : (double)r.num / (double)r.den;
}
int main() {
//所有代码执行之前要调用av_register_all和avformat_network_init
//初始化所有的封装和解封装 flv mp4 mp3 mov。不包含编码和解码
av_register_all();

//初始化网络库
avformat_network_init();

//使用的相对路径,执行文件在bin目录下。test.mp4放到bin目录下即可
const char *inUrl = "test.flv";
//输出的地址
const char *outUrl = "rtmp://192.168.136.131/live/test";

//////////////////////////////////////////////////////////////////
//                   输入流处理部分
/////////////////////////////////////////////////////////////////
//打开文件,解封装 avformat_open_input
//AVFormatContext **ps  输入封装的上下文。包含所有的格式内容和所有的IO。如果是文件就是文件IO,网络就对应网络IO
//const char *url  路径
//AVInputFormt * fmt 封装器
//AVDictionary ** options 参数设置
AVFormatContext *ictx = NULL;

//打开文件,解封文件头
int ret = avformat_open_input(&ictx, inUrl, 0, NULL);
if (ret < 0) {
    return avError(ret);
}
cout << "avformat_open_input success!" << endl;
//获取音频视频的信息 .h264 flv 没有头信息
ret = avformat_find_stream_info(ictx, 0);
if (ret != 0) {
    return avError(ret);
}
//打印视频视频信息
//0打印所有  inUrl 打印时候显示,
av_dump_format(ictx, 0, inUrl, 0);

//////////////////////////////////////////////////////////////////
//                   输出流处理部分
/////////////////////////////////////////////////////////////////
AVFormatContext * octx = NULL;
//如果是输入文件 flv可以不传,可以从文件中判断。如果是流则必须传
//创建输出上下文
ret = avformat_alloc_output_context2(&octx, NULL, "flv", outUrl);
if (ret < 0) {
    return avError(ret);
}
cout << "avformat_alloc_output_context2 success!" << endl;
//配置输出流
//AVIOcontext *pb  //IO上下文
//AVStream **streams  指针数组,存放多个输出流  视频音频字幕流
//int nb_streams;
//duration ,bit_rate

//AVStream
//AVRational time_base
//AVCodecParameters *codecpar 音视频参数
//AVCodecContext *codec
//遍历输入的AVStream
for (int i = 0; i < ictx->nb_streams; i++) {
    //创建一个新的流到octx中
    AVStream *out = avformat_new_stream(octx, ictx->streams[i]->codec->codec);
    if (!out) {
        return avError(0);
    }
    //复制配置信息 用于mp4 过时的方法
    //ret=avcodec_copy_context(out->codec, ictx->streams[i]->codec);
    ret = avcodec_parameters_copy(out->codecpar, ictx->streams[i]->codecpar);
    if (ret < 0) {
        return avError(ret);
    }
    out->codec->codec_tag = 0;
}
av_dump_format(octx, 0, outUrl, 1);

//////////////////////////////////////////////////////////////////
//                   准备推流
/////////////////////////////////////////////////////////////////

//打开IO
ret = avio_open(&octx->pb, outUrl, AVIO_FLAG_WRITE);
if (ret < 0) {
    avError(ret);
}

//写入头部信息
ret = avformat_write_header(octx, 0);
if (ret < 0) {
    avError(ret);
}
cout << "avformat_write_header Success!" << endl;

//推流每一帧数据
//int64_t pts  [ pts*(num/den)  第几秒显示]
//int64_t dts  解码时间 [P帧(相对于上一帧的变化) I帧(关键帧,完整的数据) B帧(上一帧和下一帧的变化)]  有了B帧压缩率更高。
//uint8_t *data    
//int size
//int stream_index
//int flag
AVPacket avPacket;
//获取当前的时间戳  微妙
long long startTime = av_gettime();
while (true)
{
    ret = av_read_frame(ictx, &avPacket);
    if (ret < 0) {
        break;
    }
    cout << avPacket.pts << " " << flush;
    //计算转换时间戳 pts dts
    //获取时间基数
    AVRational itime = ictx->streams[avPacket.stream_index]->time_base;
    AVRational otime = octx->streams[avPacket.stream_index]->time_base;
    avPacket.pts = av_rescale_q_rnd(avPacket.pts, itime, otime, (AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_NEAR_INF));
    avPacket.dts = av_rescale_q_rnd(avPacket.pts, itime, otime, (AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_NEAR_INF));
    //到这一帧时候经历了多长时间
    avPacket.duration = av_rescale_q_rnd(avPacket.duration, itime, otime, (AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_NEAR_INF));
    avPacket.pos = -1;
    //视频帧推送速度
    if (ictx->streams[avPacket.stream_index]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
        AVRational tb = ictx->streams[avPacket.stream_index]->time_base;
        //已经过去的时间
        long long now = av_gettime() - startTime;
        long long dts = 0;
        dts = avPacket.dts * (1000 * 1000 * r2d(tb));
        if (dts > now)
            av_usleep(dts - now);
        else {
            cout << "sss";
        }
    }
    //推送  会自动释放空间 不需要调用av_packet_unref
    ret = av_interleaved_write_frame(octx, &avPacket);
    if (ret < 0) {
        break;
    }
    //视频帧推送速度
    //if (avPacket.stream_index == 0)
    //  av_usleep(30 * 1000);
    //释放空间。内部指向的视频空间和音频空间
    //av_packet_unref(&avPacket);
}
return 0;

}

int avError(int errNum) {
char buf[1024];
//获取错误信息
av_strerror(errNum, buf, sizeof(buf));
cout << " failed! " << buf << endl;
return -1;
}


#include
using namespace std;
//引入头文件
extern "C"
{
#include "libavformat/avformat.h"
//引入时间
#include "libavutil/time.h"
}
//引入库
#pragma comment(lib,"avformat.lib")
//工具库,包括获取错误信息等
#pragma comment(lib,"avutil.lib")
//编解码的库
#pragma comment(lib,"avcodec.lib")

int avError(int errNum);

static double r2d(AVRational r)
{
return r.num == 0 || r.den == 0 ? 0. : (double)r.num / (double)r.den;
}
int main() {
int videoindex = -1;
//所有代码执行之前要调用av_register_all和avformat_network_init
//初始化所有的封装和解封装 flv mp4 mp3 mov。不包含编码和解码
av_register_all();

//初始化网络库
avformat_network_init();

//使用的相对路径,执行文件在bin目录下。test.mp4放到bin目录下即可
const char *inUrl = "hs.mp4";
//输出的地址
const char *outUrl = "rtmp://192.166.11.13/live";

//////////////////////////////////////////////////////////////////
//                   输入流处理部分
/////////////////////////////////////////////////////////////////
//打开文件,解封装 avformat_open_input
//AVFormatContext **ps  输入封装的上下文。包含所有的格式内容和所有的IO。如果是文件就是文件IO,网络就对应网络IO
//const char *url  路径
//AVInputFormt * fmt 封装器
//AVDictionary ** options 参数设置
AVFormatContext *ictx = NULL;

AVOutputFormat *ofmt = NULL;

//打开文件,解封文件头
int ret = avformat_open_input(&ictx, inUrl, 0, NULL);
if (ret < 0) {
    return avError(ret);
}
cout << "avformat_open_input success!" << endl;
//获取音频视频的信息 .h264 flv 没有头信息
ret = avformat_find_stream_info(ictx, 0);
if (ret != 0) {
    return avError(ret);
}
//打印视频视频信息
//0打印所有  inUrl 打印时候显示,
av_dump_format(ictx, 0, inUrl, 0);

//////////////////////////////////////////////////////////////////
//                   输出流处理部分
/////////////////////////////////////////////////////////////////
AVFormatContext * octx = NULL;
//如果是输入文件 flv可以不传,可以从文件中判断。如果是流则必须传
//创建输出上下文
ret = avformat_alloc_output_context2(&octx, NULL, "flv", outUrl);
if (ret < 0) {
    return avError(ret);
}
cout << "avformat_alloc_output_context2 success!" << endl;

ofmt = octx->oformat;
cout << "nb_streams  " << ictx->nb_streams << endl;
int i;
//for (i = 0; i < ictx->nb_streams; i++) {
//  cout << "i " << i <<"  "<< ictx->nb_streams<< endl;
//  AVStream *in_stream = ictx->streams[i];
//  AVCodec *codec = avcodec_find_decoder(in_stream->codecpar->codec_id);
//  AVStream *out_stream = avformat_new_stream(octx, codec);
//  if (!out_stream) {
//      printf("Failed allocating output stream\n");
//      ret = AVERROR_UNKNOWN;
//  }
//  AVCodecContext *pCodecCtx = avcodec_alloc_context3(codec);
//  ret = avcodec_parameters_to_context(pCodecCtx, in_stream->codecpar);
//  if (ret < 0) {
//      printf("Failed to copy context input to output stream codec context\n");
//  }
//  pCodecCtx->codec_tag = 0;
//  if (octx->oformat->flags & AVFMT_GLOBALHEADER) {
//      pCodecCtx->flags |= CODEC_FLAG_GLOBAL_HEADER;
//  }
//  ret = avcodec_parameters_from_context(out_stream->codecpar, pCodecCtx);
//  if (ret < 0) {
//      printf("Failed to copy context input to output stream codec context\n");
//  }
//}

for (i = 0; i < ictx->nb_streams; i++) {

    //获取输入视频流
    AVStream *in_stream = ictx->streams[i];
    //为输出上下文添加音视频流(初始化一个音视频流容器)
    AVStream *out_stream = avformat_new_stream(octx, in_stream->codec->codec);
    if (!out_stream) {
        printf("未能成功添加音视频流\n");
        ret = AVERROR_UNKNOWN;
    }

    //将输入编解码器上下文信息 copy 给输出编解码器上下文
    //ret = avcodec_copy_context(out_stream->codec, in_stream->codec);
    ret = avcodec_parameters_copy(out_stream->codecpar, in_stream->codecpar);
    //ret = avcodec_parameters_from_context(out_stream->codecpar, in_stream->codec);
    //ret = avcodec_parameters_to_context(out_stream->codec, in_stream->codecpar);
    if (ret < 0) {
        printf("copy 编解码器上下文失败\n");
    }
    out_stream->codecpar->codec_tag = 0;

    out_stream->codec->codec_tag = 0;
    if (octx->oformat->flags & AVFMT_GLOBALHEADER) {
        out_stream->codec->flags = out_stream->codec->flags | CODEC_FLAG_GLOBAL_HEADER;
    }
}

//输入流数据的数量循环
for (i = 0; i < ictx->nb_streams; i++) {
    if (ictx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
        videoindex = i;
        break;
    }
}

av_dump_format(octx, 0, outUrl, 1);

//////////////////////////////////////////////////////////////////
//                   准备推流
/////////////////////////////////////////////////////////////////

//打开IO
ret = avio_open(&octx->pb, outUrl, AVIO_FLAG_WRITE);
if (ret < 0) {
    avError(ret);
}

//写入头部信息
ret = avformat_write_header(octx, 0);
if (ret < 0) {
    avError(ret);
}
cout << "avformat_write_header Success!" << endl;
//推流每一帧数据
//int64_t pts  [ pts*(num/den)  第几秒显示]
//int64_t dts  解码时间 [P帧(相对于上一帧的变化) I帧(关键帧,完整的数据) B帧(上一帧和下一帧的变化)]  有了B帧压缩率更高。
//uint8_t *data    
//int size
//int stream_index
//int flag
AVPacket pkt;
//获取当前的时间戳  微妙
long long start_time = av_gettime();
long long frame_index = 0;
while (1) {
    //输入输出视频流
    AVStream *in_stream, *out_stream;
    //获取解码前数据
    ret = av_read_frame(ictx, &pkt);
    if (ret < 0) {
        break;
    }

    /*
    PTS(Presentation Time Stamp)显示播放时间
    DTS(Decoding Time Stamp)解码时间
    */
    //没有显示时间(比如未解码的 H.264 )
    if (pkt.pts == AV_NOPTS_VALUE) {
        //AVRational time_base:时基。通过该值可以把PTS,DTS转化为真正的时间。
        AVRational time_base1 = ictx->streams[videoindex]->time_base;

        //计算两帧之间的时间
        /*
        r_frame_rate 基流帧速率  (不是太懂)
        av_q2d 转化为double类型
        */
        int64_t calc_duration = (double)AV_TIME_BASE / av_q2d(ictx->streams[videoindex]->r_frame_rate);

        //配置参数
        pkt.pts = (double)(frame_index*calc_duration) / (double)(av_q2d(time_base1)*AV_TIME_BASE);
        pkt.dts = pkt.pts;
        pkt.duration = (double)calc_duration / (double)(av_q2d(time_base1)*AV_TIME_BASE);
    }

    //延时
    if (pkt.stream_index == videoindex) {
        AVRational time_base = ictx->streams[videoindex]->time_base;
        AVRational time_base_q = { 1,AV_TIME_BASE };
        //计算视频播放时间
        int64_t pts_time = av_rescale_q(pkt.dts, time_base, time_base_q);
        //计算实际视频的播放时间
        int64_t now_time = av_gettime() - start_time;

        AVRational avr = ictx->streams[videoindex]->time_base;
        cout << avr.num << " " << avr.den << "  "<<pkt.dts <<"  "<<pkt.pts<<"   "<< pts_time <<endl;
        if (pts_time > now_time) {
            //睡眠一段时间(目的是让当前视频记录的播放时间与实际时间同步)
            av_usleep((unsigned int)(pts_time - now_time));
        }
    }

    in_stream = ictx->streams[pkt.stream_index];
    out_stream = octx->streams[pkt.stream_index];

    //计算延时后,重新指定时间戳
    pkt.pts = av_rescale_q_rnd(pkt.pts, in_stream->time_base, out_stream->time_base,(AVRounding) (AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
    pkt.dts = av_rescale_q_rnd(pkt.dts, in_stream->time_base, out_stream->time_base, (AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
    pkt.duration = (int)av_rescale_q(pkt.duration, in_stream->time_base, out_stream->time_base);
    //字节流的位置,-1 表示不知道字节流位置
    pkt.pos = -1;

    if (pkt.stream_index == videoindex) {
        printf("Send %8d video frames to output URL\n", frame_index);
        frame_index++;
    }

    //向输出上下文发送(向地址推送)
    ret = av_interleaved_write_frame(octx, &pkt);

    if (ret < 0) {
        printf("发送数据包出错\n");
        break;
    }

    //释放
    av_free_packet(&pkt);
}
return 0;

}

int avError(int errNum) {
    char buf[1024];
    //获取错误信息
    av_strerror(errNum, buf, sizeof(buf));
    cout << " failed! " << buf << endl;
    return -1;
}

https://www.jianshu.com/p/69eede147229
https://www.jianshu.com/p/6b9ab2652147
https://blog.csdn.net/jacke121/article/details/80298256

- 阅读全文 -


Copyright©2024 春天花会开, All Rights Reserved. Email: webmaster@oroct.com