mirror of
https://github.com/barry-ran/QtScrcpy.git
synced 2025-04-20 19:44:59 +00:00
update:mp4录制功能完善
This commit is contained in:
parent
ea9deb3b9f
commit
79d5a0ca77
11 changed files with 179 additions and 90 deletions
|
@ -111,7 +111,6 @@ static qint32 readPacketWithMeta(void *opaque, uint8_t *buf, int bufSize) {
|
|||
// It is followed by <packet_size> bytes containing the packet/frame.
|
||||
|
||||
if (!state->remaining) {
|
||||
#define HEADER_SIZE 12
|
||||
quint8 header[HEADER_SIZE];
|
||||
qint32 r = decoder->recvData(header, HEADER_SIZE);
|
||||
if (r == -1) {
|
||||
|
@ -121,7 +120,9 @@ static qint32 readPacketWithMeta(void *opaque, uint8_t *buf, int bufSize) {
|
|||
return AVERROR_EOF;
|
||||
}
|
||||
// no partial read (net_recv_all())
|
||||
Q_ASSERT(r == HEADER_SIZE);
|
||||
if (r != HEADER_SIZE) {
|
||||
return AVERROR(ENOMEM);
|
||||
}
|
||||
|
||||
uint64_t pts = bufferRead64be(header);
|
||||
state->remaining = bufferRead32be(&header[8]);
|
||||
|
@ -155,9 +156,16 @@ static qint32 readPacketWithMeta(void *opaque, uint8_t *buf, int bufSize) {
|
|||
static qint32 readRawPacket(void *opaque, quint8 *buf, qint32 bufSize) {
|
||||
Decoder *decoder = (Decoder*)opaque;
|
||||
if (decoder) {
|
||||
return decoder->recvData(buf, bufSize);
|
||||
qint32 len = decoder->recvData(buf, bufSize);
|
||||
if (len == -1) {
|
||||
return AVERROR(errno);
|
||||
}
|
||||
if (len == 0) {
|
||||
return AVERROR_EOF;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
return 0;
|
||||
return AVERROR_EOF;
|
||||
}
|
||||
|
||||
void Decoder::setDeviceSocket(DeviceSocket* deviceSocket)
|
||||
|
@ -177,15 +185,9 @@ qint32 Decoder::recvData(quint8* buf, qint32 bufSize)
|
|||
}
|
||||
if (m_deviceSocket) {
|
||||
qint32 len = m_deviceSocket->subThreadRecvData(buf, bufSize);
|
||||
if (len == -1) {
|
||||
return AVERROR(errno);
|
||||
}
|
||||
if (len == 0) {
|
||||
return AVERROR_EOF;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
return AVERROR_EOF;
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool Decoder::startDecode()
|
||||
|
@ -204,7 +206,7 @@ void Decoder::stopDecode()
|
|||
if (m_frames) {
|
||||
m_frames->stop();
|
||||
}
|
||||
//wait();
|
||||
wait();
|
||||
}
|
||||
|
||||
Decoder::ReceiverState *Decoder::getReceiverState()
|
||||
|
|
|
@ -59,7 +59,7 @@ private:
|
|||
Frames* m_frames;
|
||||
|
||||
// for recorder
|
||||
Recorder* m_recorder;
|
||||
Recorder* m_recorder = Q_NULLPTR;
|
||||
ReceiverState m_receiverState;
|
||||
};
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include <QFile>
|
||||
#include <QTime>
|
||||
#include <QKeyEvent>
|
||||
#include <QFileDialog>
|
||||
|
||||
#include "dialog.h"
|
||||
#include "ui_dialog.h"
|
||||
|
@ -86,10 +87,22 @@ void Dialog::on_updateDevice_clicked()
|
|||
void Dialog::on_startServerBtn_clicked()
|
||||
{
|
||||
if (!m_videoForm) {
|
||||
QString absFilePath;
|
||||
QString fileDir(ui->recordPathEdt->text().trimmed());
|
||||
if (!fileDir.isEmpty()) {
|
||||
QDateTime dateTime = QDateTime::currentDateTime();
|
||||
QString fileName = dateTime.toString("_yyyyMMdd_hhmmss.zzz");
|
||||
fileName = windowTitle() + fileName + ".mp4";
|
||||
QDir dir(fileDir);
|
||||
absFilePath = dir.absoluteFilePath(fileName);
|
||||
}
|
||||
|
||||
quint32 bitRate = ui->bitRateBox->currentText().trimmed().toUInt();
|
||||
// this is ok that "native" toUshort is 0
|
||||
quint16 videoSize = ui->videoSizeBox->currentText().trimmed().toUShort();
|
||||
m_videoForm = new VideoForm(ui->serialBox->currentText().trimmed(), videoSize, bitRate);
|
||||
m_videoForm = new VideoForm(ui->serialBox->currentText().trimmed(), videoSize, bitRate, absFilePath);
|
||||
|
||||
outLog("start server...");
|
||||
}
|
||||
m_videoForm->show();
|
||||
}
|
||||
|
@ -98,6 +111,7 @@ void Dialog::on_stopServerBtn_clicked()
|
|||
{
|
||||
if (m_videoForm) {
|
||||
m_videoForm->close();
|
||||
outLog("stop server...", false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -180,3 +194,20 @@ void Dialog::on_wirelessDisConnectBtn_clicked()
|
|||
adbArgs << addr;
|
||||
m_adb.execute("", adbArgs);
|
||||
}
|
||||
|
||||
void Dialog::on_selectRecordPathBtn_clicked()
|
||||
{
|
||||
QFileDialog::Options options = QFileDialog::DontResolveSymlinks | QFileDialog::ShowDirsOnly;
|
||||
QString directory = QFileDialog::getExistingDirectory(this,
|
||||
tr("select path"),
|
||||
"",
|
||||
options);
|
||||
if (!directory.isEmpty()) {
|
||||
ui->recordPathEdt->setText(directory);
|
||||
}
|
||||
}
|
||||
|
||||
void Dialog::on_recordPathEdt_textChanged(const QString &arg1)
|
||||
{
|
||||
ui->recordPathEdt->setToolTip(arg1);
|
||||
}
|
||||
|
|
|
@ -37,6 +37,10 @@ private slots:
|
|||
|
||||
void on_wirelessDisConnectBtn_clicked();
|
||||
|
||||
void on_selectRecordPathBtn_clicked();
|
||||
|
||||
void on_recordPathEdt_textChanged(const QString &arg1);
|
||||
|
||||
private:
|
||||
bool checkAdbRun();
|
||||
void initUI();
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>560</width>
|
||||
<height>486</height>
|
||||
<height>577</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
|
@ -26,18 +26,62 @@
|
|||
<string notr="true">QtScrcpy</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="2" column="0">
|
||||
<widget class="QTextEdit" name="outEdit">
|
||||
<property name="documentTitle">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
<item row="1" column="0">
|
||||
<widget class="QGroupBox" name="usbGroupBox">
|
||||
<property name="title">
|
||||
<string>USB line</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="3" column="2">
|
||||
<widget class="QPushButton" name="getIPBtn">
|
||||
<property name="text">
|
||||
<string>get device ip</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="3">
|
||||
<widget class="QPushButton" name="stopServerBtn">
|
||||
<property name="text">
|
||||
<string>stop server</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QPushButton" name="updateDevice">
|
||||
<property name="text">
|
||||
<string>update device</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="3">
|
||||
<widget class="QPushButton" name="startAdbdBtn">
|
||||
<property name="text">
|
||||
<string>start adbd</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>device serial:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QComboBox" name="serialBox"/>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QPushButton" name="startServerBtn">
|
||||
<property name="text">
|
||||
<string>start server</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<item row="2" column="0">
|
||||
<widget class="QGroupBox" name="wirelessGroupBox">
|
||||
<property name="title">
|
||||
<string>Wireless</string>
|
||||
</property>
|
||||
|
@ -98,40 +142,26 @@
|
|||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QGroupBox" name="topGroupBox">
|
||||
<property name="title">
|
||||
<string>USB line</string>
|
||||
<item row="3" column="0">
|
||||
<widget class="QTextEdit" name="outEdit">
|
||||
<property name="documentTitle">
|
||||
<string/>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="1" column="1">
|
||||
<widget class="QComboBox" name="serialBox"/>
|
||||
</item>
|
||||
<item row="1" column="3">
|
||||
<widget class="QPushButton" name="stopServerBtn">
|
||||
<property name="text">
|
||||
<string>stop server</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QPushButton" name="startServerBtn">
|
||||
<property name="text">
|
||||
<string>start server</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>device serial:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>bit rate:</string>
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QGroupBox" name="configGroupBox">
|
||||
<property name="title">
|
||||
<string>Config</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_3">
|
||||
<item row="0" column="3">
|
||||
<widget class="QComboBox" name="videoSizeBox">
|
||||
<property name="toolTip">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
@ -152,31 +182,31 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="3">
|
||||
<widget class="QComboBox" name="videoSizeBox">
|
||||
<property name="toolTip">
|
||||
<string/>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>bit rate:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="3">
|
||||
<widget class="QPushButton" name="startAdbdBtn">
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>start adbd</string>
|
||||
<string>record save path:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="2">
|
||||
<widget class="QPushButton" name="getIPBtn">
|
||||
<property name="text">
|
||||
<string>get device ip</string>
|
||||
<item row="1" column="1" colspan="2">
|
||||
<widget class="QLineEdit" name="recordPathEdt">
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QPushButton" name="updateDevice">
|
||||
<item row="1" column="3">
|
||||
<widget class="QPushButton" name="selectRecordPathBtn">
|
||||
<property name="text">
|
||||
<string>update device</string>
|
||||
<string>select path</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
|
|
@ -84,6 +84,6 @@ void myMessageOutput(QtMsgType type, const QMessageLogContext &context, const QS
|
|||
}
|
||||
}
|
||||
if (QtFatalMsg == type) {
|
||||
abort();
|
||||
//abort();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,9 +2,8 @@
|
|||
|
||||
#include "recorder.h"
|
||||
|
||||
Recorder::Recorder(const QString& fileName, const QSize& declaredFrameSize)
|
||||
Recorder::Recorder(const QString& fileName)
|
||||
: m_fileName(fileName)
|
||||
, m_declaredFrameSize(declaredFrameSize)
|
||||
{
|
||||
|
||||
}
|
||||
|
@ -14,6 +13,11 @@ Recorder::~Recorder()
|
|||
|
||||
}
|
||||
|
||||
void Recorder::setFrameSize(const QSize &declaredFrameSize)
|
||||
{
|
||||
m_declaredFrameSize = declaredFrameSize;
|
||||
}
|
||||
|
||||
bool Recorder::open(AVCodec *inputCodec)
|
||||
{
|
||||
const AVOutputFormat* mp4 = findMp4Muxer();
|
||||
|
@ -38,6 +42,7 @@ bool Recorder::open(AVCodec *inputCodec)
|
|||
AVStream* outStream = avformat_new_stream(m_formatCtx, inputCodec);
|
||||
if (!outStream) {
|
||||
avformat_free_context(m_formatCtx);
|
||||
m_formatCtx = Q_NULLPTR;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -70,6 +75,7 @@ bool Recorder::open(AVCodec *inputCodec)
|
|||
qCritical(QString("Failed to open output file: %1").arg(m_fileName).toUtf8().toStdString().c_str());
|
||||
// ostream will be cleaned up during context cleaning
|
||||
avformat_free_context(m_formatCtx);
|
||||
m_formatCtx = Q_NULLPTR;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -78,6 +84,7 @@ bool Recorder::open(AVCodec *inputCodec)
|
|||
qCritical(QString("Failed to write header to %1").arg(m_fileName).toUtf8().toStdString().c_str());
|
||||
avio_closep(&m_formatCtx->pb);
|
||||
avformat_free_context(m_formatCtx);
|
||||
m_formatCtx = Q_NULLPTR;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -86,12 +93,17 @@ bool Recorder::open(AVCodec *inputCodec)
|
|||
|
||||
void Recorder::close()
|
||||
{
|
||||
int ret = av_write_trailer(m_formatCtx);
|
||||
if (ret < 0) {
|
||||
qCritical(QString("Failed to write trailer to %1").arg(m_fileName).toUtf8().toStdString().c_str());
|
||||
if (Q_NULLPTR != m_formatCtx) {
|
||||
int ret = av_write_trailer(m_formatCtx);
|
||||
if (ret < 0) {
|
||||
qCritical(QString("Failed to write trailer to %1").arg(m_fileName).toUtf8().toStdString().c_str());
|
||||
} else {
|
||||
qInfo(QString("success record %1").arg(m_fileName).toStdString().c_str());
|
||||
}
|
||||
avio_close(m_formatCtx->pb);
|
||||
avformat_free_context(m_formatCtx);
|
||||
m_formatCtx = Q_NULLPTR;
|
||||
}
|
||||
avio_close(m_formatCtx->pb);
|
||||
avformat_free_context(m_formatCtx);
|
||||
}
|
||||
|
||||
bool Recorder::write(AVPacket *packet)
|
||||
|
|
|
@ -11,9 +11,10 @@ extern "C"
|
|||
class Recorder
|
||||
{
|
||||
public:
|
||||
Recorder(const QString& fileName, const QSize& declaredFrameSize);
|
||||
Recorder(const QString& fileName);
|
||||
virtual ~Recorder();
|
||||
|
||||
void setFrameSize(const QSize& declaredFrameSize);
|
||||
bool open(AVCodec* inputCodec);
|
||||
void close();
|
||||
bool write(AVPacket* packet);
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
#include "controlevent.h"
|
||||
#include "recorder.h"
|
||||
|
||||
VideoForm::VideoForm(const QString& serial, quint16 maxSize, quint32 bitRate,QWidget *parent) :
|
||||
VideoForm::VideoForm(const QString& serial, quint16 maxSize, quint32 bitRate, const QString& fileName, QWidget *parent) :
|
||||
QWidget(parent),
|
||||
ui(new Ui::videoForm),
|
||||
m_serial(serial),
|
||||
|
@ -30,10 +30,12 @@ VideoForm::VideoForm(const QString& serial, quint16 maxSize, quint32 bitRate,QWi
|
|||
initUI();
|
||||
|
||||
m_server = new Server();
|
||||
m_recorder = new Recorder("./test.mp4", QSize(600, 300));
|
||||
m_frames.init();
|
||||
m_decoder.setFrames(&m_frames);
|
||||
m_decoder.setRecoder(m_recorder);
|
||||
if (!fileName.trimmed().isEmpty()) {
|
||||
m_recorder = new Recorder(fileName.trimmed());
|
||||
m_decoder.setRecoder(m_recorder);
|
||||
}
|
||||
|
||||
initSignals();
|
||||
|
||||
|
@ -56,11 +58,13 @@ VideoForm::VideoForm(const QString& serial, quint16 maxSize, quint32 bitRate,QWi
|
|||
|
||||
VideoForm::~VideoForm()
|
||||
{
|
||||
m_server->stop();
|
||||
// server must stop before decoder, because decoder block main thread
|
||||
m_decoder.stopDecode();
|
||||
m_server->stop();
|
||||
m_decoder.wait();
|
||||
delete m_server;
|
||||
delete m_recorder;
|
||||
if (m_recorder) {
|
||||
delete m_recorder;
|
||||
}
|
||||
m_frames.deInit();
|
||||
delete ui;
|
||||
}
|
||||
|
@ -132,7 +136,12 @@ void VideoForm::initSignals()
|
|||
setWindowTitle(deviceName);
|
||||
updateShowSize(size);
|
||||
|
||||
// init decode
|
||||
// init recorder
|
||||
if (m_recorder) {
|
||||
m_recorder->setFrameSize(size);
|
||||
}
|
||||
|
||||
// init decoder
|
||||
m_decoder.setDeviceSocket(m_server->getDeviceSocket());
|
||||
m_decoder.startDecode();
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ class VideoForm : public QWidget
|
|||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit VideoForm(const QString& serial, quint16 maxSize = 720, quint32 bitRate = 8000000, QWidget *parent = 0);
|
||||
explicit VideoForm(const QString& serial, quint16 maxSize = 720, quint32 bitRate = 8000000, const QString& fileName = "", QWidget *parent = 0);
|
||||
~VideoForm();
|
||||
|
||||
void switchFullScreen();
|
||||
|
|
4
TODO.txt
4
TODO.txt
|
@ -1,5 +1,5 @@
|
|||
mp4录制如何保证正确收到最后的数据
|
||||
|
||||
mp4录制:server启动时间,翻译
|
||||
横屏防止工具窗口超出屏幕
|
||||
工具栏扩展(模拟点击指定次数等)
|
||||
|
||||
模拟点击改用手指(注意:辅助按键就都没了)
|
||||
|
|
Loading…
Add table
Reference in a new issue