mirror of
https://github.com/barry-ran/QtScrcpy.git
synced 2025-08-03 14:18:45 +00:00
add:录像支持mkv
This commit is contained in:
parent
e4b3fb76d9
commit
f02bae1e70
6 changed files with 90 additions and 30 deletions
|
@ -74,6 +74,10 @@ void Dialog::initUI()
|
||||||
ui->videoSizeBox->addItem("1080");
|
ui->videoSizeBox->addItem("1080");
|
||||||
ui->videoSizeBox->addItem("native");
|
ui->videoSizeBox->addItem("native");
|
||||||
ui->videoSizeBox->setCurrentIndex(1);
|
ui->videoSizeBox->setCurrentIndex(1);
|
||||||
|
|
||||||
|
ui->formatBox->addItem("mp4");
|
||||||
|
ui->formatBox->addItem("mkv");
|
||||||
|
ui->videoSizeBox->setCurrentIndex(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Dialog::on_updateDevice_clicked()
|
void Dialog::on_updateDevice_clicked()
|
||||||
|
@ -92,8 +96,9 @@ void Dialog::on_startServerBtn_clicked()
|
||||||
QString fileDir(ui->recordPathEdt->text().trimmed());
|
QString fileDir(ui->recordPathEdt->text().trimmed());
|
||||||
if (!fileDir.isEmpty()) {
|
if (!fileDir.isEmpty()) {
|
||||||
QDateTime dateTime = QDateTime::currentDateTime();
|
QDateTime dateTime = QDateTime::currentDateTime();
|
||||||
QString fileName = dateTime.toString("_yyyyMMdd_hhmmss.zzz");
|
QString fileName = dateTime.toString("_yyyyMMdd_hhmmss_zzz");
|
||||||
fileName = windowTitle() + fileName + ".mp4";
|
QString ext = ui->formatBox->currentText().trimmed();
|
||||||
|
fileName = windowTitle() + fileName + "." + ext;
|
||||||
QDir dir(fileDir);
|
QDir dir(fileDir);
|
||||||
absFilePath = dir.absoluteFilePath(fileName);
|
absFilePath = dir.absoluteFilePath(fileName);
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,19 +6,19 @@
|
||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>502</width>
|
<width>639</width>
|
||||||
<height>600</height>
|
<height>600</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="minimumSize">
|
<property name="minimumSize">
|
||||||
<size>
|
<size>
|
||||||
<width>502</width>
|
<width>520</width>
|
||||||
<height>0</height>
|
<height>0</height>
|
||||||
</size>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
<property name="maximumSize">
|
<property name="maximumSize">
|
||||||
<size>
|
<size>
|
||||||
<width>502</width>
|
<width>639</width>
|
||||||
<height>16777215</height>
|
<height>16777215</height>
|
||||||
</size>
|
</size>
|
||||||
</property>
|
</property>
|
||||||
|
@ -158,6 +158,20 @@
|
||||||
<string>Config</string>
|
<string>Config</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QGridLayout" name="gridLayout_3">
|
<layout class="QGridLayout" name="gridLayout_3">
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QLabel" name="label_5">
|
||||||
|
<property name="text">
|
||||||
|
<string>record save path:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="4">
|
||||||
|
<widget class="QLabel" name="label_6">
|
||||||
|
<property name="text">
|
||||||
|
<string>format:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item row="0" column="3">
|
<item row="0" column="3">
|
||||||
<widget class="QComboBox" name="videoSizeBox">
|
<widget class="QComboBox" name="videoSizeBox">
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
|
@ -165,6 +179,13 @@
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QLabel" name="label_3">
|
||||||
|
<property name="text">
|
||||||
|
<string>bit rate:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item row="0" column="1">
|
<item row="0" column="1">
|
||||||
<widget class="QComboBox" name="bitRateBox">
|
<widget class="QComboBox" name="bitRateBox">
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
|
@ -182,28 +203,17 @@
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="0" column="0">
|
<item row="0" column="5">
|
||||||
<widget class="QLabel" name="label_3">
|
<widget class="QComboBox" name="formatBox"/>
|
||||||
<property name="text">
|
|
||||||
<string>bit rate:</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
</item>
|
||||||
<item row="1" column="0">
|
<item row="1" column="1" colspan="3">
|
||||||
<widget class="QLabel" name="label_5">
|
|
||||||
<property name="text">
|
|
||||||
<string>record save path:</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="1" column="1" colspan="2">
|
|
||||||
<widget class="QLineEdit" name="recordPathEdt">
|
<widget class="QLineEdit" name="recordPathEdt">
|
||||||
<property name="readOnly">
|
<property name="readOnly">
|
||||||
<bool>true</bool>
|
<bool>true</bool>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="1" column="3">
|
<item row="1" column="4" colspan="2">
|
||||||
<widget class="QPushButton" name="selectRecordPathBtn">
|
<widget class="QPushButton" name="selectRecordPathBtn">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>select path</string>
|
<string>select path</string>
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
#include <QFileInfo>
|
||||||
|
|
||||||
#include "recorder.h"
|
#include "recorder.h"
|
||||||
|
|
||||||
|
@ -16,6 +17,7 @@ static const AVRational SCRCPY_TIME_BASE = {1, 1000000}; // timestamps in us
|
||||||
|
|
||||||
Recorder::Recorder(const QString& fileName)
|
Recorder::Recorder(const QString& fileName)
|
||||||
: m_fileName(fileName)
|
: m_fileName(fileName)
|
||||||
|
, m_format(guessRecordFormat(fileName))
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -30,11 +32,18 @@ void Recorder::setFrameSize(const QSize &declaredFrameSize)
|
||||||
m_declaredFrameSize = declaredFrameSize;
|
m_declaredFrameSize = declaredFrameSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Recorder::setFormat(Recorder::RecorderFormat format)
|
||||||
|
{
|
||||||
|
m_format = format;
|
||||||
|
}
|
||||||
|
|
||||||
bool Recorder::open(AVCodec *inputCodec)
|
bool Recorder::open(AVCodec *inputCodec)
|
||||||
{
|
{
|
||||||
const AVOutputFormat* mp4 = findMp4Muxer();
|
QString formatName = recorderGetFormatName(m_format);
|
||||||
if (!mp4) {
|
Q_ASSERT(!formatName.isEmpty());
|
||||||
qCritical("Could not find mp4 muxer");
|
const AVOutputFormat* format = findMuxer(formatName.toUtf8());
|
||||||
|
if (!format) {
|
||||||
|
qCritical("Could not find muxer");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,7 +58,7 @@ bool Recorder::open(AVCodec *inputCodec)
|
||||||
// still expects a pointer-to-non-const (it has not be updated accordingly)
|
// still expects a pointer-to-non-const (it has not be updated accordingly)
|
||||||
// <https://github.com/FFmpeg/FFmpeg/commit/0694d8702421e7aff1340038559c438b61bb30dd>
|
// <https://github.com/FFmpeg/FFmpeg/commit/0694d8702421e7aff1340038559c438b61bb30dd>
|
||||||
|
|
||||||
m_formatCtx->oformat = (AVOutputFormat*)mp4;
|
m_formatCtx->oformat = (AVOutputFormat*)format;
|
||||||
|
|
||||||
AVStream* outStream = avformat_new_stream(m_formatCtx, inputCodec);
|
AVStream* outStream = avformat_new_stream(m_formatCtx, inputCodec);
|
||||||
if (!outStream) {
|
if (!outStream) {
|
||||||
|
@ -115,7 +124,7 @@ bool Recorder::write(AVPacket *packet)
|
||||||
return av_write_frame(m_formatCtx, packet) >= 0;
|
return av_write_frame(m_formatCtx, packet) >= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const AVOutputFormat *Recorder::findMp4Muxer()
|
const AVOutputFormat *Recorder::findMuxer(const char* name)
|
||||||
{
|
{
|
||||||
#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(58, 9, 100)
|
#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(58, 9, 100)
|
||||||
void* opaque = Q_NULLPTR;
|
void* opaque = Q_NULLPTR;
|
||||||
|
@ -127,8 +136,8 @@ const AVOutputFormat *Recorder::findMp4Muxer()
|
||||||
#else
|
#else
|
||||||
outFormat = av_oformat_next(outFormat);
|
outFormat = av_oformat_next(outFormat);
|
||||||
#endif
|
#endif
|
||||||
// until null or with name "mp4"
|
// until null or with name "name"
|
||||||
} while (outFormat && strcmp(outFormat->name, "mp4"));
|
} while (outFormat && strcmp(outFormat->name, name));
|
||||||
return outFormat;
|
return outFormat;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -167,3 +176,29 @@ void Recorder::recorderRescalePacket(AVPacket *packet)
|
||||||
AVStream *ostream = m_formatCtx->streams[0];
|
AVStream *ostream = m_formatCtx->streams[0];
|
||||||
av_packet_rescale_ts(packet, SCRCPY_TIME_BASE, ostream->time_base);
|
av_packet_rescale_ts(packet, SCRCPY_TIME_BASE, ostream->time_base);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString Recorder::recorderGetFormatName(Recorder::RecorderFormat format)
|
||||||
|
{
|
||||||
|
switch (format) {
|
||||||
|
case RECORDER_FORMAT_MP4: return "mp4";
|
||||||
|
case RECORDER_FORMAT_MKV: return "matroska";
|
||||||
|
default: return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Recorder::RecorderFormat Recorder::guessRecordFormat(const QString &fileName)
|
||||||
|
{
|
||||||
|
if (4 > fileName.length()) {
|
||||||
|
return Recorder::RECORDER_FORMAT_NULL;
|
||||||
|
}
|
||||||
|
QFileInfo fileInfo = QFileInfo(fileName);
|
||||||
|
QString ext = fileInfo.suffix();
|
||||||
|
if (0 == ext.compare("mp4")) {
|
||||||
|
return Recorder::RECORDER_FORMAT_MP4;
|
||||||
|
}
|
||||||
|
if (0 == ext.compare("mkv")) {
|
||||||
|
return Recorder::RECORDER_FORMAT_MKV;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Recorder::RECORDER_FORMAT_NULL;
|
||||||
|
}
|
||||||
|
|
|
@ -11,24 +11,34 @@ extern "C"
|
||||||
class Recorder
|
class Recorder
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
enum RecorderFormat {
|
||||||
|
RECORDER_FORMAT_NULL = 0,
|
||||||
|
RECORDER_FORMAT_MP4,
|
||||||
|
RECORDER_FORMAT_MKV,
|
||||||
|
};
|
||||||
|
|
||||||
Recorder(const QString& fileName);
|
Recorder(const QString& fileName);
|
||||||
virtual ~Recorder();
|
virtual ~Recorder();
|
||||||
|
|
||||||
void setFrameSize(const QSize& declaredFrameSize);
|
void setFrameSize(const QSize& declaredFrameSize);
|
||||||
|
void setFormat(Recorder::RecorderFormat format);
|
||||||
bool open(AVCodec* inputCodec);
|
bool open(AVCodec* inputCodec);
|
||||||
void close();
|
void close();
|
||||||
bool write(AVPacket* packet);
|
bool write(AVPacket* packet);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const AVOutputFormat* findMp4Muxer();
|
const AVOutputFormat* findMuxer(const char* name);
|
||||||
bool recorderWriteHeader(AVPacket* packet);
|
bool recorderWriteHeader(AVPacket* packet);
|
||||||
void recorderRescalePacket(AVPacket *packet);
|
void recorderRescalePacket(AVPacket *packet);
|
||||||
|
QString recorderGetFormatName(Recorder::RecorderFormat format);
|
||||||
|
RecorderFormat guessRecordFormat(const QString& fileName);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString m_fileName = "";
|
QString m_fileName = "";
|
||||||
AVFormatContext* m_formatCtx = Q_NULLPTR;
|
AVFormatContext* m_formatCtx = Q_NULLPTR;
|
||||||
QSize m_declaredFrameSize;
|
QSize m_declaredFrameSize;
|
||||||
bool m_headerWritten = false;
|
bool m_headerWritten = false;
|
||||||
|
RecorderFormat m_format = RECORDER_FORMAT_NULL;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // RECORDER_H
|
#endif // RECORDER_H
|
||||||
|
|
|
@ -13,11 +13,11 @@
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
|
|
||||||
#include "videoform.h"
|
#include "videoform.h"
|
||||||
|
#include "recorder.h"
|
||||||
#include "ui_videoform.h"
|
#include "ui_videoform.h"
|
||||||
#include "iconhelper.h"
|
#include "iconhelper.h"
|
||||||
#include "toolform.h"
|
#include "toolform.h"
|
||||||
#include "controlevent.h"
|
#include "controlevent.h"
|
||||||
#include "recorder.h"
|
|
||||||
#include "mousetap/mousetap.h"
|
#include "mousetap/mousetap.h"
|
||||||
|
|
||||||
VideoForm::VideoForm(const QString& serial, quint16 maxSize, quint32 bitRate, const QString& fileName, QWidget *parent) :
|
VideoForm::VideoForm(const QString& serial, quint16 maxSize, quint32 bitRate, const QString& fileName, QWidget *parent) :
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue