update:mp4录制功能完善

This commit is contained in:
Barry 2019-01-27 13:37:49 +08:00
commit 4557795f14
11 changed files with 179 additions and 90 deletions

View file

@ -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. // It is followed by <packet_size> bytes containing the packet/frame.
if (!state->remaining) { if (!state->remaining) {
#define HEADER_SIZE 12
quint8 header[HEADER_SIZE]; quint8 header[HEADER_SIZE];
qint32 r = decoder->recvData(header, HEADER_SIZE); qint32 r = decoder->recvData(header, HEADER_SIZE);
if (r == -1) { if (r == -1) {
@ -121,7 +120,9 @@ static qint32 readPacketWithMeta(void *opaque, uint8_t *buf, int bufSize) {
return AVERROR_EOF; return AVERROR_EOF;
} }
// no partial read (net_recv_all()) // no partial read (net_recv_all())
Q_ASSERT(r == HEADER_SIZE); if (r != HEADER_SIZE) {
return AVERROR(ENOMEM);
}
uint64_t pts = bufferRead64be(header); uint64_t pts = bufferRead64be(header);
state->remaining = bufferRead32be(&header[8]); 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) { static qint32 readRawPacket(void *opaque, quint8 *buf, qint32 bufSize) {
Decoder *decoder = (Decoder*)opaque; Decoder *decoder = (Decoder*)opaque;
if (decoder) { if (decoder) {
return decoder->recvData(buf, bufSize); qint32 len = decoder->recvData(buf, bufSize);
if (len == -1) {
return AVERROR(errno);
} }
return 0; if (len == 0) {
return AVERROR_EOF;
}
return len;
}
return AVERROR_EOF;
} }
void Decoder::setDeviceSocket(DeviceSocket* deviceSocket) void Decoder::setDeviceSocket(DeviceSocket* deviceSocket)
@ -177,15 +185,9 @@ qint32 Decoder::recvData(quint8* buf, qint32 bufSize)
} }
if (m_deviceSocket) { if (m_deviceSocket) {
qint32 len = m_deviceSocket->subThreadRecvData(buf, bufSize); qint32 len = m_deviceSocket->subThreadRecvData(buf, bufSize);
if (len == -1) {
return AVERROR(errno);
}
if (len == 0) {
return AVERROR_EOF;
}
return len; return len;
} }
return AVERROR_EOF; return 0;
} }
bool Decoder::startDecode() bool Decoder::startDecode()
@ -204,7 +206,7 @@ void Decoder::stopDecode()
if (m_frames) { if (m_frames) {
m_frames->stop(); m_frames->stop();
} }
//wait(); wait();
} }
Decoder::ReceiverState *Decoder::getReceiverState() Decoder::ReceiverState *Decoder::getReceiverState()

View file

@ -59,7 +59,7 @@ private:
Frames* m_frames; Frames* m_frames;
// for recorder // for recorder
Recorder* m_recorder; Recorder* m_recorder = Q_NULLPTR;
ReceiverState m_receiverState; ReceiverState m_receiverState;
}; };

View file

@ -1,6 +1,7 @@
#include <QFile> #include <QFile>
#include <QTime> #include <QTime>
#include <QKeyEvent> #include <QKeyEvent>
#include <QFileDialog>
#include "dialog.h" #include "dialog.h"
#include "ui_dialog.h" #include "ui_dialog.h"
@ -86,10 +87,22 @@ void Dialog::on_updateDevice_clicked()
void Dialog::on_startServerBtn_clicked() void Dialog::on_startServerBtn_clicked()
{ {
if (!m_videoForm) { 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(); quint32 bitRate = ui->bitRateBox->currentText().trimmed().toUInt();
// this is ok that "native" toUshort is 0 // this is ok that "native" toUshort is 0
quint16 videoSize = ui->videoSizeBox->currentText().trimmed().toUShort(); 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(); m_videoForm->show();
} }
@ -98,6 +111,7 @@ void Dialog::on_stopServerBtn_clicked()
{ {
if (m_videoForm) { if (m_videoForm) {
m_videoForm->close(); m_videoForm->close();
outLog("stop server...", false);
} }
} }
@ -180,3 +194,20 @@ void Dialog::on_wirelessDisConnectBtn_clicked()
adbArgs << addr; adbArgs << addr;
m_adb.execute("", adbArgs); 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);
}

View file

@ -37,6 +37,10 @@ private slots:
void on_wirelessDisConnectBtn_clicked(); void on_wirelessDisConnectBtn_clicked();
void on_selectRecordPathBtn_clicked();
void on_recordPathEdt_textChanged(const QString &arg1);
private: private:
bool checkAdbRun(); bool checkAdbRun();
void initUI(); void initUI();

View file

@ -7,7 +7,7 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>560</width> <width>560</width>
<height>486</height> <height>577</height>
</rect> </rect>
</property> </property>
<property name="minimumSize"> <property name="minimumSize">
@ -26,18 +26,62 @@
<string notr="true">QtScrcpy</string> <string notr="true">QtScrcpy</string>
</property> </property>
<layout class="QGridLayout" name="gridLayout_2"> <layout class="QGridLayout" name="gridLayout_2">
<item row="2" column="0"> <item row="1" column="0">
<widget class="QTextEdit" name="outEdit"> <widget class="QGroupBox" name="usbGroupBox">
<property name="documentTitle"> <property name="title">
<string/> <string>USB line</string>
</property> </property>
<property name="readOnly"> <layout class="QGridLayout" name="gridLayout">
<bool>true</bool> <item row="3" column="2">
<widget class="QPushButton" name="getIPBtn">
<property name="text">
<string>get device ip</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="1" column="0"> <item row="0" column="3">
<widget class="QGroupBox" name="groupBox"> <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="2" column="0">
<widget class="QGroupBox" name="wirelessGroupBox">
<property name="title"> <property name="title">
<string>Wireless</string> <string>Wireless</string>
</property> </property>
@ -98,40 +142,26 @@
</layout> </layout>
</widget> </widget>
</item> </item>
<item row="3" column="0">
<widget class="QTextEdit" name="outEdit">
<property name="documentTitle">
<string/>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="0"> <item row="0" column="0">
<widget class="QGroupBox" name="topGroupBox"> <widget class="QGroupBox" name="configGroupBox">
<property name="title"> <property name="title">
<string>USB line</string> <string>Config</string>
</property> </property>
<layout class="QGridLayout" name="gridLayout"> <layout class="QGridLayout" name="gridLayout_3">
<item row="1" column="1"> <item row="0" column="3">
<widget class="QComboBox" name="serialBox"/> <widget class="QComboBox" name="videoSizeBox">
</item> <property name="toolTip">
<item row="1" column="3"> <string/>
<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> </property>
</widget> </widget>
</item> </item>
@ -152,31 +182,31 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="0" column="3"> <item row="0" column="0">
<widget class="QComboBox" name="videoSizeBox"> <widget class="QLabel" name="label_3">
<property name="toolTip"> <property name="text">
<string/> <string>bit rate:</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="4" column="3"> <item row="1" column="0">
<widget class="QPushButton" name="startAdbdBtn"> <widget class="QLabel" name="label_5">
<property name="text"> <property name="text">
<string>start adbd</string> <string>record save path:</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="4" column="2"> <item row="1" column="1" colspan="2">
<widget class="QPushButton" name="getIPBtn"> <widget class="QLineEdit" name="recordPathEdt">
<property name="text"> <property name="readOnly">
<string>get device ip</string> <bool>true</bool>
</property> </property>
</widget> </widget>
</item> </item>
<item row="4" column="1"> <item row="1" column="3">
<widget class="QPushButton" name="updateDevice"> <widget class="QPushButton" name="selectRecordPathBtn">
<property name="text"> <property name="text">
<string>update device</string> <string>select path</string>
</property> </property>
</widget> </widget>
</item> </item>

View file

@ -84,6 +84,6 @@ void myMessageOutput(QtMsgType type, const QMessageLogContext &context, const QS
} }
} }
if (QtFatalMsg == type) { if (QtFatalMsg == type) {
abort(); //abort();
} }
} }

View file

@ -2,9 +2,8 @@
#include "recorder.h" #include "recorder.h"
Recorder::Recorder(const QString& fileName, const QSize& declaredFrameSize) Recorder::Recorder(const QString& fileName)
: m_fileName(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) bool Recorder::open(AVCodec *inputCodec)
{ {
const AVOutputFormat* mp4 = findMp4Muxer(); const AVOutputFormat* mp4 = findMp4Muxer();
@ -38,6 +42,7 @@ bool Recorder::open(AVCodec *inputCodec)
AVStream* outStream = avformat_new_stream(m_formatCtx, inputCodec); AVStream* outStream = avformat_new_stream(m_formatCtx, inputCodec);
if (!outStream) { if (!outStream) {
avformat_free_context(m_formatCtx); avformat_free_context(m_formatCtx);
m_formatCtx = Q_NULLPTR;
return false; 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()); qCritical(QString("Failed to open output file: %1").arg(m_fileName).toUtf8().toStdString().c_str());
// ostream will be cleaned up during context cleaning // ostream will be cleaned up during context cleaning
avformat_free_context(m_formatCtx); avformat_free_context(m_formatCtx);
m_formatCtx = Q_NULLPTR;
return false; 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()); qCritical(QString("Failed to write header to %1").arg(m_fileName).toUtf8().toStdString().c_str());
avio_closep(&m_formatCtx->pb); avio_closep(&m_formatCtx->pb);
avformat_free_context(m_formatCtx); avformat_free_context(m_formatCtx);
m_formatCtx = Q_NULLPTR;
return false; return false;
} }
@ -86,12 +93,17 @@ bool Recorder::open(AVCodec *inputCodec)
void Recorder::close() void Recorder::close()
{ {
if (Q_NULLPTR != m_formatCtx) {
int ret = av_write_trailer(m_formatCtx); int ret = av_write_trailer(m_formatCtx);
if (ret < 0) { if (ret < 0) {
qCritical(QString("Failed to write trailer to %1").arg(m_fileName).toUtf8().toStdString().c_str()); 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); avio_close(m_formatCtx->pb);
avformat_free_context(m_formatCtx); avformat_free_context(m_formatCtx);
m_formatCtx = Q_NULLPTR;
}
} }
bool Recorder::write(AVPacket *packet) bool Recorder::write(AVPacket *packet)

View file

@ -11,9 +11,10 @@ extern "C"
class Recorder class Recorder
{ {
public: public:
Recorder(const QString& fileName, const QSize& declaredFrameSize); Recorder(const QString& fileName);
virtual ~Recorder(); virtual ~Recorder();
void setFrameSize(const QSize& declaredFrameSize);
bool open(AVCodec* inputCodec); bool open(AVCodec* inputCodec);
void close(); void close();
bool write(AVPacket* packet); bool write(AVPacket* packet);

View file

@ -19,7 +19,7 @@
#include "controlevent.h" #include "controlevent.h"
#include "recorder.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), QWidget(parent),
ui(new Ui::videoForm), ui(new Ui::videoForm),
m_serial(serial), m_serial(serial),
@ -30,10 +30,12 @@ VideoForm::VideoForm(const QString& serial, quint16 maxSize, quint32 bitRate,QWi
initUI(); initUI();
m_server = new Server(); m_server = new Server();
m_recorder = new Recorder("./test.mp4", QSize(600, 300));
m_frames.init(); m_frames.init();
m_decoder.setFrames(&m_frames); m_decoder.setFrames(&m_frames);
if (!fileName.trimmed().isEmpty()) {
m_recorder = new Recorder(fileName.trimmed());
m_decoder.setRecoder(m_recorder); m_decoder.setRecoder(m_recorder);
}
initSignals(); initSignals();
@ -56,11 +58,13 @@ VideoForm::VideoForm(const QString& serial, quint16 maxSize, quint32 bitRate,QWi
VideoForm::~VideoForm() VideoForm::~VideoForm()
{ {
m_decoder.stopDecode();
m_server->stop(); m_server->stop();
m_decoder.wait(); // server must stop before decoder, because decoder block main thread
m_decoder.stopDecode();
delete m_server; delete m_server;
if (m_recorder) {
delete m_recorder; delete m_recorder;
}
m_frames.deInit(); m_frames.deInit();
delete ui; delete ui;
} }
@ -132,7 +136,12 @@ void VideoForm::initSignals()
setWindowTitle(deviceName); setWindowTitle(deviceName);
updateShowSize(size); updateShowSize(size);
// init decode // init recorder
if (m_recorder) {
m_recorder->setFrameSize(size);
}
// init decoder
m_decoder.setDeviceSocket(m_server->getDeviceSocket()); m_decoder.setDeviceSocket(m_server->getDeviceSocket());
m_decoder.startDecode(); m_decoder.startDecode();

View file

@ -22,7 +22,7 @@ class VideoForm : public QWidget
Q_OBJECT Q_OBJECT
public: 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(); ~VideoForm();
void switchFullScreen(); void switchFullScreen();

View file

@ -1,5 +1,5 @@
mp4录制如何保证正确收到最后的数据 mp4录制server启动时间翻译
横屏防止工具窗口超出屏幕
工具栏扩展(模拟点击指定次数等) 工具栏扩展(模拟点击指定次数等)
模拟点击改用手指(注意:辅助按键就都没了) 模拟点击改用手指(注意:辅助按键就都没了)