I.はじめに
ローカル カメラ ストリーミングは、ローカル デスクトップ ストリーミングと似ていますが、コレクション デバイスのソースがデスクトップではなくローカル カメラ デバイスに置き換えられていることと、他のコードはまったく同じです。ローカル カメラからリアルタイム ビデオを収集する場合、解像度とフレーム レートを設定する場合は、デバイス自体がサポートしている必要があることに注意してください。サポートしていない場合は停止します。たとえば、最大解像度デバイス自体は 1280x720 で、1080x720 をキャプチャするように解像度を積極的に設定すると、収集できない画像は失敗します. デフォルトで設定されていない場合、通常、640x480 の解像度と 25 フレーム レートを使用して収集します. ローカル カメラ デバイスをキャプチャするコマンド ラインは、ffmpeg -f dshow -i video="USB Video Device":audio="microphone (USB Audio Device)" -vcodec libx264 -preset:v ultrafast -tune:v zerolatency -f rtsp です。 rtsp:/ /192.168.0.110:6907/stream 、オーディオとビデオが利用できるように、マイクを使用するように指定できます。
一般的な収集手順:
- フォーマット av_find_input_format、パラメーター dshow/v4l2/avfoundation を見つけます。
- デスクトップ avformat_open_input、パラメーター video=USB ビデオ デバイスを開きます
- ビデオ ストリームを検索 av_find_best_stream
- デコーダーを検索 avcodec_find_decoder
- デコーダを開く avcodec_open2
- ループ読み取り av_read_frame
- ビデオのデコード avcodec_send_packet/avcodec_receive_frame
- リリースを閉じる avcodec_free_context/avformat_close_input
プッシュ フローの一般的な手順:
- 出力を作成 avformat_alloc_output_context2
- ビデオ ストリームの作成 avformat_new_stream
- 出力avio_openを開き、プッシュストリームの完全なアドレスをパラメーターとして入力します
- 書き込み開始文字 avformat_write_header
- 書き込みフレーム データ av_interleaved_write_frame
- リリースを閉じる avio_close/avformat_free_context
2. レンダリング
3. 体験アドレス
- 国内サイト: https: //gitee.com/feiyangqingyun
- 国際サイト: https://github.com/feiyangqingyun
- 個人作品:https://blog.csdn.net/feiyangqingyun/article/details/97565652
- 体験アドレス:https://pan.baidu.com/s/1d7TH_GEYl5nOecuNlWJJ7g抽出コード:01jf ファイル名:bin_video_push.
4. 関連コード
void FFmpegThread::initInputFormat()
{
//本地摄像头/桌面录屏
if (videoType == VideoType_Camera) {
#if defined(Q_OS_WIN)
//ifmt = av_find_input_format("vfwcap");
ifmt = av_find_input_format("dshow");
#elif defined(Q_OS_LINUX)
//可以打开cheese程序查看本地摄像头(如果是在虚拟机中需要设置usb选项3.1)
//ifmt = av_find_input_format("v4l2");
ifmt = av_find_input_format("video4linux2");
#elif defined(Q_OS_MAC)
ifmt = av_find_input_format("avfoundation");
#endif
} else if (videoType == VideoType_Desktop) {
#if defined(Q_OS_WIN)
ifmt = av_find_input_format("gdigrab");
#elif defined(Q_OS_LINUX)
ifmt = av_find_input_format("x11grab");
#elif defined(Q_OS_MAC)
ifmt = av_find_input_format("avfoundation");
#endif
}
}
bool FFmpegThread::initInput()
{
//实例化格式处理上下文
formatCtx = avformat_alloc_context();
//设置超时回调(有些不存在的地址或者网络不好的情况下要卡很久)
formatCtx->interrupt_callback.callback = FFmpegHelper::avinterruptCallBackFun;
formatCtx->interrupt_callback.opaque = this;
//打开输入(通过标志位控制回调那边做超时判断)
//其他地方调用 formatCtx->url formatCtx->filename 可以拿到设置的地址(两个变量值一样)
tryOpen = true;
QByteArray urlData = VideoHelper::getRightUrl(videoType, videoUrl).toUtf8();
int result = avformat_open_input(&formatCtx, urlData.data(), ifmt, &options);
tryOpen = false;
if (result < 0) {
debug("打开出错", "错误: " + FFmpegHelper::getError(result));
return false;
}
//根据自己项目需要开启下面部分代码加快视频流打开速度
//开启后由于值太小可能会出现部分视频流获取不到分辨率
if (decodeType == DecodeType_Fastest && videoType == VideoType_Rtsp) {
//接口内部读取的最大数据量(从源文件中读取的最大字节数)
//默认值5000000导致这里卡很久最耗时(可以调小来加快打开速度)
formatCtx->probesize = 50000;
//从文件中读取的最大时长(单位为 AV_TIME_BASE units)
formatCtx->max_analyze_duration = 5 * AV_TIME_BASE;
//内部读取的数据包不放入缓冲区
//formatCtx->flags |= AVFMT_FLAG_NOBUFFER;
//设置解码错误验证过滤花屏
//formatCtx->error_recognition |= AV_EF_EXPLODE;
}
//获取流信息
result = avformat_find_stream_info(formatCtx, NULL);
if (result < 0) {
debug("找流失败", "错误: " + FFmpegHelper::getError(result));
return false;
}
//解码格式
formatName = formatCtx->iformat->name;
//某些格式比如视频流不做音视频同步(响应速度快)
if (formatName == "rtsp" || videoUrl.endsWith(".sdp")) {
useSync = false;
}
//设置了最快速度则不启用音视频同步
if (decodeType == DecodeType_Fastest) {
useSync = false;
}
//有些格式不支持硬解码
if (formatName.contains("rm") || formatName.contains("avi") || formatName.contains("webm")) {
hardware = "none";
}
//本地摄像头设备解码出来的直接就是yuv显示不需要硬解码
if (videoType == VideoType_Camera || videoType == VideoType_Desktop) {
useSync = false;
hardware = "none";
}
//过低版本不支持硬解码
#if (FFMPEG_VERSION_MAJOR < 3)
hardware = "none";
#endif
//获取文件时长(这里获取到的是秒)
double length = (double)formatCtx->duration / AV_TIME_BASE;
duration = length * 1000;
this->checkVideoType();
//有时候网络地址也可能是纯音频
if (videoType == VideoType_FileHttp) {
onlyAudio = VideoHelper::getOnlyAudio(videoUrl, formatName);
}
if (getIsFile()) {
//文件必须要音视频同步
useSync = true;
//发送文件时长信号
emit receiveDuration(duration > 0 ? duration : 0);
}
QString msg = QString("格式: %1 时长: %2 秒 加速: %3").arg(formatName).arg(duration / 1000).arg(hardware);
debug("媒体信息", msg);
return true;
}
5. 特長
5.1 ファイルストリーミング
- ネットワーク カードとリッスン ポートを指定し、ネットワーク リクエストを受信して、オーディオやビデオなどのさまざまなファイルをプッシュします。
- リアルタイム統計には、各ファイルに対応する訪問数、合計訪問数、および異なる IP アドレスからの訪問数が表示されます。
- 0-ダイレクトプレイ、1-ダウンロードプレイの複数モードを指定可能。
- リアルタイム印刷では、さまざまな送受信要求および応答データが表示されます。
- 各ファイルは MD5 で暗号化された一意の識別子に対応しており、アクセスするファイルを識別するためにアドレス サフィックスを要求するために使用されます。
- さまざまなブラウザー (Google chromium/Microsoft edge/Firefox firefox など)、さまざまなプレーヤー (vlc/mpv/ffplay/potplayer/mpchc など) をサポートして、リクエストを開きます。
- 再生処理中は、再生の進行を任意に切り替えることができ、倍速再生に対応しています。
- ストリーミングが必要なファイルの名前履歴が自動的に保存され、アプリケーションをロードするために開かれます。
- ファイルを切り替えてアクセスアドレスを取得し、アドレスをクリップボードに自動的にコピーして、直接貼り付けてテストします。
- 非常に低い CPU 使用率、128 チャンネル 1080P 同時ストリーミングは 1% 未満の CPU 使用率、非同期データ送信メカニズムです。
- 純粋な QTcpSocket 通信は、ストリーミング メディア サービス プログラムに依存しません。コア ソース コードは 500 行未満で、詳細な注釈と完全な機能を備えています。
- Qt4/Qt5/Qt6 の任意のバージョンをサポートし、任意のシステム (windows/linux/macos/android/embedded linux など) をサポートします。
5.2 ネットワークストリーミング
- さまざまなローカル ビデオ ファイルとネットワーク ビデオ ファイルをサポートします。
- さまざまなネットワーク ビデオ ストリーム、Web カメラ、rtsp、rtmp、http などのプロトコルをサポートします。
- ローカル カメラ デバイスのストリーミングをサポートし、解像度とフレーム レートを指定できます。
- 画面領域やフレーム レートなどを指定して、ローカル デスクトップのストリーミングをサポートします。
- ストリーミング メディア サービス プログラム、デフォルトの mediamtx (以前の rtsp-simple-server) を自動的に開始します。srs、EasyDarwin、LiveQing、ZLMediaKit などを選択できます。
- 動画ファイルをリアルタイムで切り替えてプレビューできます。
- ストリーミングの明瞭度と品質を調整できます。
- ファイル、ディレクトリ、およびアドレスを動的に追加できます。
- ビデオ ファイルは自動的にループでストリーミングされます。ビデオ ソースがビデオ ストリームの場合、切断された後、自動的に再接続されます。
- ネットワーク ビデオ ストリームは自動的に再接続され、再接続は成功し、ストリーミングは自動的に続行されます。
- ネットワークビデオストリーミングのリアルタイム性は非常に高く、遅延は非常に少なく、遅延時間は約100msです。
- ストリームをプッシュした後、rtmp アドレスを使用してアクセスするほか、直接 hls/webrtc アクセスにも対応し、ブラウザを直接開いてリアルタイム画面を表示できます。
- Qt4/Qt5/Qt6 の任意のバージョンをサポートし、任意のシステム (windows/linux/macos/android/embedded linux など) をサポートします。