Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Request Player Basic Functions #417

Closed
binarysoft2011 opened this issue Nov 20, 2023 · 58 comments
Closed

Request Player Basic Functions #417

binarysoft2011 opened this issue Nov 20, 2023 · 58 comments

Comments

@binarysoft2011
Copy link

binarysoft2011 commented Nov 20, 2023

I'm very interested your QtAVPlayer based on FFmpeg. Thanks for your contribution of source code.
I'll test it on Windows, Android, macOS and iOS.

May I ask some questions?
I search video player basic functions

  1. audio mute,

  2. audio channels(Left, Right, Mono, Stereo) not found in your code.
    I use setFilter for channels, It's working. But I think player has basic channels function in it.

  3. playback current position (video timeline)
    I want to get current position of video for video time line.
    So I get position of every sec with timer.

m_positionTimer.setInterval(1000); connect(&m_positionTimer, &QTimer::timeout, this, &MAVPlayer::updatePosition);

` connect(&m_positionTimer, &QTimer::timeout, this, &MAVPlayer::updatePosition);`

`connect(&m_player, &QAVPlayer::stateChanged, this, [this](QAVPlayer::State state) {
    if (state == QAVPlayer::PausedState || state == QAVPlayer::StoppedState) {
        m_positionTimer.stop();
    } else if (state == QAVPlayer::PlayingState) {
        m_positionTimer.start();
    }
});`

void updatePosition() { if (m_player.state() == QAVPlayer::PlayingState) { qint64 currentPosition = m_player.position() / 1000; emit positionChanged(currentPosition); } }

or Is there onPositionChange in your code?

  1. I stop video or end of media, last frame of video is still display.

Thanks.

@valbok
Copy link
Owner

valbok commented Nov 20, 2023

  1. audio mute,

Since the player sends audio frames, there are two options:

  1. Don't play them and it is handled by the application like
    if (!muted) audioOutput.play(audioFrame);
  2. it is possible to disable decoding audio frames at all, when all streams are parsed:
    player.setAudioStreams({}); - it will not decode audio frames at all and no frames will be sent. This will save some CPU. Note there might be many audio channels.

@valbok
Copy link
Owner

valbok commented Nov 20, 2023

playback current position (video timeline)
I want to get current position of video for video time line.
So I get position of every sec with timer.

2 options there:

  1. Since you receive the video frames, you could get frame.pts() in sec and update the timeline based on this
  2. QAVPlayer::position() provides more accurate position, with respect to seeks, and eof. - which is more preferred. But needs to be called by timer as usual when the position is needed.

@valbok
Copy link
Owner

valbok commented Nov 20, 2023

audio channels(Left, Right, Mono, Stereo) not found in your code.
I use setFilter for channels, It's working. But I think player has basic channels function in it.

This is not yet supported, but looks it is possible to implement. Since QAudioSink is used from QtMM. Right now QAVAudioOutput is suggested to play audio, but it uses the audio format from the audio frames. But maybe it is possible to override channels. Will check

@valbok
Copy link
Owner

valbok commented Nov 20, 2023

  1. I stop video or end of media, last frame of video is still display.

The player guarantees that all frames are sent to an app, but it does not send empty frame on eof, cancel or stop.
But if you receive QAVPlayer::NoMedia it means that no frames left and you could flush/render to empty frame.

Btw QAVPlayer::stop() does not cancel the decoding, it pauses the pipeline: pauses decoding and sending frames.
Calling ::play() will resume playing.
But QAVPlayer::pause() provides also next frame if it was not paused before.

@binarysoft2011
Copy link
Author

Thanks for your suggestion and answer. I'll try them as your suggest.

@binarysoft2011
Copy link
Author

binarysoft2011 commented Nov 20, 2023

  1. add audioOutput.play(audioFrame) or omit it before playing is working.

But I want to toggle audio mute during video playing.
if(!mute) audioOutput.play(audioFrame);
else audioOutput.play({}); // QAVAudioFrame frame; audioOutput.play(frame);
is not working.

  1. if(bMute) {
    tmpAudioStreams = m_player.currentAudioStreams();
    m_player.setAudioStreams({});
    }
    else m_player.setAudioStreams(tmpAudioStreams);
    is working but after unmute audio is noising for a few seconds or sometime it's fine.

so I test with toggle mute or unmute during playing as your suggestion attach or unattach m_audioOutput.play(m_AudioFrame).

if(bMute)
    QObject::disconnect(&m_player, &QAVPlayer::audioFrame, this, &MAVPlayer::handleAudioFrame);
else
    QObject::connect(&m_player, &QAVPlayer::audioFrame, this, &MAVPlayer::handleAudioFrame);

void handleAudioFrame(const QAVAudioFrame &frame)
{
m_audioOutput.play(m_AudioFrame);
}
it's working for temporary solution. Other better ways may be.

@valbok
Copy link
Owner

valbok commented Nov 20, 2023

If you would like to toggle audio, looks the best way is

handleAudioFrame(const QAVPlayer::audioFrame &frame ) {
   if (!muted) m_audioOutput.play(frame);
}

@binarysoft2011
Copy link
Author

binarysoft2011 commented Nov 20, 2023

Yes.
toggle mute is working
muted = !muted;
handleAudioFrame(const QAVPlayer::audioFrame &frame ) {
if (!muted) m_audioOutput.play(frame);
}
Now I remove disconnect, connect from it.
Thanks for best way.

@binarysoft2011
Copy link
Author

I test player in windows 10 64bit computer.
play mpg, mp4, url. All results are fine.
computer with GPU, player shows
Using hardware decoding in d3d11
All results are fine.

in windows 7 32bit computer.
not supported hardware decoding.
Using software decoding in yuv420p.
so when I play, volume cannot change after player is paused then resume play or seek eg. seek(1000*50)
some mpg format video's sound is nosy.

Is the using hardware decoding depend upon hardware or windows?
Now I'll install same hardware computer with windows 10 64bit and windows 7 32bit and test player on these computers.

I apologize for log with picture. Next time I try with text.

8FA35263-7A66-4DE3-8E5C-4DC26DC4FF4B_medium

@valbok
Copy link
Owner

valbok commented Nov 21, 2023

Is the using hardware decoding depend upon hardware or windows?

It depends on pixel format of the video frames, ffmpeg hw accel imp and if QAVPlayer supports it. Never tried Windows 7,

About the log, do you see "Using hardware device context:" ? If not shown, means ffmpeg does not support AV_HWDEVICE_TYPE_D3D11VA.

Suspicious that there is QIODevice: Cannot call seek, maybe you play from QIODevice and try to seek?

@valbok
Copy link
Owner

valbok commented Nov 21, 2023

volume cannot change after player is paused then resume play or seek eg. seek(1000*50)

It might be a bug, it is implemented there https://github.com/valbok/QtAVPlayer/blob/master/src/QtAVPlayer/qavaudiooutput.cpp#L186

Does it set the correct volume there?

@binarysoft2011
Copy link
Author

Thanks for your quick reply.
Yes, I test same hardware with windows 7, windows 10.
in win7,
when "QIODevice: seek (QIODevice): Cannot call seek on a sequential device" message is shown, sound is nosy.
Same hardware,
in win7, Using software decoding in yuv420p.
in win10, 11, Using hardware decoding in d3d11

@valbok
Copy link
Owner

valbok commented Nov 21, 2023

when "QIODevice: seek (QIODevice): Cannot call seek on a sequential device" message is shown, sound is nosy.

is sound ok before seek?

@binarysoft2011
Copy link
Author

binarysoft2011 commented Nov 21, 2023

Yes sound is ok, before seek. After seek, volume cannot change especially old mpeg format video.
"QIODevice: seek (QIODevice): Cannot call seek on a sequential device" message is shown, while player playing video from url.

Now I installed DirectX. sound is ok.
Is volume range 0 to 1?

@valbok
Copy link
Owner

valbok commented Nov 21, 2023

Is volume range 0 to 1?

yes, https://doc.qt.io/qt-5.15/qaudiooutput.html#setVolume

btw volume is not related to ffmpeg, you receive audio frames and can render them using audio device

@binarysoft2011
Copy link
Author

Video Forward and Backward while video is playing.
Like old DVD player when I press FWD during playing, video is fast forward playing. Press FWD again to get normal play.
BWD is also fast backward function.

For fast forward, setSpeed can be used. But it is not backward.
So I have to use seek, stepForward/stepBackward.
seek with timer may work.
But steps are work only one frame then paused. So I think It can not be used with timer.

@valbok
Copy link
Owner

valbok commented Nov 21, 2023

Like old DVD player when I press FWD during playing, video is fast forward playing. Press FWD again to get normal play.
BWD is also fast backward function.

Originally forward/backward was implemented to send only one frame, and make a pause.

What you mean about "fast forward playing", like increasing speed?

@binarysoft2011
Copy link
Author

binarysoft2011 commented Nov 21, 2023

What you mean about "fast forward playing", like increasing speed?

FWD fast forward is playing faster forward speed eg. 2X, 3X, 4X faster than normal playback speed (like setSpeed)
BWD fast backward is faster rewind during video is playing.

So I use eg. position + seek(10) per 1000 msec for fast forward. position - seek(10) per 1500 msec for fast backward (rewind)

@binarysoft2011
Copy link
Author

binarysoft2011 commented Nov 21, 2023

May I ask more questions?

  1. Multi Video outputs.
    Now I already test multi video output and It is working.
  2. Can player play QByteArray? (I read video file and send as QByteArray via network from other qt c++ project. Can player play video receiving QByteArray during transferring and before file is close. (how to call streaming?))
  3. When playing video from url, can buffer size be set?
  4. Player can play only video display from a mp4 and play audio from other file at the same time. (how to call external audio track?)

@valbok
Copy link
Owner

valbok commented Nov 22, 2023

So I use eg. position + seek(10) per 1000 msec for fast forward. position - seek(10) per 1500 msec for fast backward (rewind)

Looks it is possible to workaround? Why you need timer here? Just do seek(pos+10/100/1000)?

@valbok
Copy link
Owner

valbok commented Nov 22, 2023

Multi Video outputs.
Now I already test multi video output and It is working.

Nice to hear this. Just to make sure,

  1. one source with filters can provide video frame with filterName() which will point to the output.
  2. Or decoding video from many streams. so stream() can point to the stream

@valbok
Copy link
Owner

valbok commented Nov 22, 2023

Can player play QByteArray? (I read video file and send as QByteArray via network from other qt c++ project. Can player > play video receiving QByteArray during transferring and before file is close. (how to call streaming?))

QtAVPlayer supports playing from QIODevice

QFile file(QLatin1String(":/alarm.wav"));
file.open(QIODevice::ReadOnly));
player.setSource("alarm", &file);

So you would need to implement QIODevice which will return raw data, which might be transmitted over network. Never tried myself, but AFAIK for some projects it was implemented reading from stdin and playing the stream.

@valbok
Copy link
Owner

valbok commented Nov 22, 2023

When playing video from url, can buffer size be set?

any iterating with network and decoding is done by ffmpeg, so it needs to find answer there.
Using QIODevice https://github.com/valbok/QtAVPlayer/blob/master/src/QtAVPlayer/qaviodevice.cpp#L119 buffer size is hardcoded, needs to be fixed

@valbok
Copy link
Owner

valbok commented Nov 22, 2023

Player can play only video display from a mp4 and play audio from other file at the same time. (how to call external audio track?)

Maybe it is possible to inject external audio stream from ffmpeg filters. QtAVPlayer does not support this. Because audio frames are synchronized with video frames using pts. You can simulate yourself like 2 players: 1 for audio, 1 for video and when you collect all audio and video frames render them synchronously.

@binarysoft2011
Copy link
Author

Why you need timer here? Just do seek(pos+10/100/1000)?
Player has buttons: FWD, BWD, Play, etc.
When I press fast buttons, I want the video is fast playing XSpeed until press FWD/BWD/Play button again or End of Media/Beginning of Media. So I click fast button, video is fast playing. Then when I stop fast playing an normal play mode, I click play/fast button.

If I do not use timer, single seek(pos+1000) will be done.

@binarysoft2011
Copy link
Author

Today, I learn and build AVPlayer, all functions are working.

I use these resources:
Qt C++ MinGW32bit 5.12.12 on Windows 11 64bit Computer.
FFmpeg 6.1 libraries that are built by MSYS2 MinGW32bit.

deployed test targets are: Windows 7 32bit, Windows 10 64bit, and Windows 11 64bit computers.
build Android API 30 (Android 11) on Android phones.

I want to also build AVPlayer for macOS, iOS. I'll show my results after that.
Is it possible to use the latest version of XCode with Qt 5.xx?

@valbok
Copy link
Owner

valbok commented Nov 27, 2023

Is it possible to use the latest version of XCode with Qt 5.xx?

Last time I tried, did not have any issues, but you should be prepared to have some since Qt 5 is a bit outdated.

@valbok
Copy link
Owner

valbok commented Dec 3, 2023

#420 is this something helpful for you?

@binarysoft2011
Copy link
Author

https://github.com/valbok/QtAVPlayer/pull/420 is this something helpful for you?
Yes, I increase/decrease value of below line.
const size_t buffer_size = 512 * 1024;
It's changes is better for playing streaming video.

@binarysoft2011
Copy link
Author

binarysoft2011 commented Dec 4, 2023

When I test player on (China) Android TV Box with [Android 12 for TV), player not play video. Sound is play just 1 sec and video is not show. So I debug and get log. some part of log are:

--------- beginning of main
12-03 16:00:17.749 15339 27688 W cedarc : RequestVideoStreamBuffer:1341: request stream buffer fail,
8385369 bytes valid data in SBM[0], total buffer size is 8388608 bytes.
12-03 16:00:17.749 15339 27688 E omx_vdec_aw: anSubmitCopy:587: req vbs fail! maybe vbs buffer is full! require_size[5579]
12-03 16:00:17.851 15339 27688 W cedarc : RequestVideoStreamBuffer:1341: request stream buffer fail,
8385369 bytes valid data in SBM[0], total buffer size is 8388608 bytes.
12-03 16:00:17.851 15339 27688 E omx_vdec_aw: anSubmitCopy:587: req vbs fail! maybe vbs buffer is full! require_size[5579]
12-03 16:00:17.953 15339 27688 W cedarc : RequestVideoStreamBuffer:1341: request stream buffer fail,
8385369 bytes valid data in SBM[0], total buffer size is 8388608 bytes.
12-03 16:00:17.953 15339 27688 E omx_vdec_aw: anSubmitCopy:587: req vbs fail! maybe vbs buffer is full! require_size[5579]
12-03 16:00:18.060 15339 27688 W cedarc : RequestVideoStreamBuffer:1341: request stream buffer fail,

......

12-03 16:00:38.235 15339 27688 E omx_vdec_aw: anSubmitCopy:587: req vbs fail! maybe vbs buffer is full! require_size[5579]
12-03 16:00:38.338 15339 27688 W cedarc : RequestVideoStreamBuffer:1341: request stream buffer fail,
8385369 bytes valid data in SBM[0], total buffer size is 8388608 bytes.
12-03 16:00:38.338 15339 27688 E omx_vdec_aw: anSubmitCopy:587: req vbs fail! maybe vbs buffer is full! require_size[5579]
12-03 16:00:38.441 15339 27688 W cedarc : RequestVideoStreamBuffer:1341: request stream buffer fail,
8385369 bytes valid data in SBM[0], total buffer size is 8388608 bytes.
12-03 16:00:38.441 15339 27688 E omx_vdec_aw: anSubmitCopy:587: req vbs fail! maybe vbs buffer is full! require_size[5579]
12-03 16:00:38.549 15339 27688 W cedarc : RequestVideoStreamBuffer:1341: request stream buffer fail,
8385369 bytes valid data in SBM[0], total buffer size is 8388608 bytes.
12-03 16:00:38.549 15339 27688 E omx_vdec_aw: anSubmitCopy:587: req vbs fail! maybe vbs buffer is full! require_size[5579]
12-03 16:00:38.656 15339 27688 W cedarc : RequestVideoStreamBuffer:1341: request stream buffer fail,
8385369 bytes valid data in SBM[0], total buffer size is 8388608 bytes.

12-03 16:00:59.917 15339 27688 E omx_vdec_aw: anSubmitCopy:587: req vbs fail! maybe vbs buffer is full! require_size[5579]
12-03 16:01:00.019 15339 27688 W cedarc : RequestVideoStreamBuffer:1341: request stream buffer fail,
8385369 bytes valid data in SBM[0], total buffer size is 8388608 bytes.
12-03 16:01:00.019 15339 27688 E omx_vdec_aw: anSubmitCopy:587: req vbs fail! maybe vbs buffer is full! require_size[5579]
12-03 16:01:00.056 3162 3266 I OpenGLRenderer: Davey! duration=9222312398287ms; Flags=0, FrameTimelineVsyncId=35558554, IntendedVsync=1059638567654664, Vsync=1059638567654664, InputEventId=0, HandleInputStart=1059638568140437, AnimationStart=1059638568145562, PerformTraversalsStart=1059638568151395, DrawStart=1059638569669145, FrameDeadline=1059638600987996, FrameInterval=1059638568131729, FrameStartTime=16666666, SyncQueued=1059638570186812, SyncStart=1059638570292854, IssueDrawCommandsStart=1059638570721187, SwapBuffers=1059638582895145, FrameCompleted=9223372036854775807, DequeueBufferDuration=48125, QueueBufferDuration=1432333, GpuCompleted=9223372036854775807, SwapBuffersCompleted=1059638585881854, DisplayPresentTime=69806945275676913,
12-03 16:01:00.126 15339 27688 W cedarc : RequestVideoStreamBuffer:1341: request stream buffer fail,
8385369 bytes valid data in SBM[0], total buffer size is 8388608 bytes.

12-03 16:01:53.432 15339 27688 E omx_vdec_aw: anSubmitCopy:587: req vbs fail! maybe vbs buffer is full! require_size[5579]
12-03 16:01:53.539 15339 27688 W cedarc : RequestVideoStreamBuffer:1341: request stream buffer fail,
8385369 bytes valid data in SBM[0], total buffer size is 8388608 bytes.
12-03 16:01:53.540 15339 27688 E omx_vdec_aw: anSubmitCopy:587: req vbs fail! maybe vbs buffer is full! require_size[5579]
12-03 16:01:53.647 15339 27688 W cedarc : RequestVideoStreamBuffer:1341: request stream buffer fail,
8385369 bytes valid data in SBM[0], total buffer size is 8388608 bytes.
12-03 16:01:53.647 15339 27688 E omx_vdec_aw: anSubmitCopy:587: req vbs fail! maybe vbs buffer is full! require_size[5579]
12-03 16:01:53.753 15339 27688 W cedarc : RequestVideoStreamBuffer:1341: request stream buffer fail,
8385369 bytes valid data in SBM[0], total buffer size is 8388608 bytes.
12-03 16:01:53.753 15339 27688 E omx_vdec_aw: anSubmitCopy:587: req vbs fail! maybe vbs buffer is full! require_size[5579]
12-03 16:01:53.855 15339 27688 W cedarc : RequestVideoStreamBuffer:1341: request stream buffer fail,
8385369 bytes valid data in SBM[0], total buffer size is 8388608 bytes.

@valbok
Copy link
Owner

valbok commented Dec 4, 2023

When I test player on (China) Android TV Box with [Android 12 for TV), player not play video. Sound is play just 1 sec and video is not show. So I debug and get log. some part of log are:

Is it rendering issue or decoding issue?
Is it stuck demuxing the video frames? Do you get video frames but they are not rendered?

@binarysoft2011
Copy link
Author

binarysoft2011 commented Dec 14, 2023

Hi,

I've Server and Client Player Projects.
Server send a audio file and client received as QByteArray and save them as file. These simple Server and Client projects are done and working.
This transfer process is too long for large file. So I want to play at once so I think play from QByteArray during transferring files.

In My Client (Player), some parts of code are
void AVPlayer::onReadyRead() {
QByteArray chunk = client->readAll(); //read data from server.
received += chunk.size();
mFile->write(chunk);
if(received == total){
mFile->close();
mFile->deleteLater();
count = 0;
}
}

I found below codes are read a file as buffer and play it.
I test it with a audio file in local storage. It can play song.

`void AVPlayer::playBuffer()
{
QFileInfo fileInfo("D:/AVPlayer/1.mp3");
QFile file(fileInfo.absoluteFilePath());
if (!file.open(QIODevice::ReadOnly)) {
qDebug() << "Could not open";
return;
}

QSharedPointer<Buffer> buffer(new Buffer);
buffer->m_size = file.size();
buffer->open(QIODevice::ReadWrite);

QSharedPointer<QAVIODevice> dev(new QAVIODevice(buffer));
m_player.setSource(fileInfo.fileName(), dev);
m_player.play();

while(!file.atEnd()) {
    auto bytes = file.read(64 * 1024);
    buffer->write(bytes);
}

}`

How can I play received (QByteArray) during transferring?

Thanks.

@valbok
Copy link
Owner

valbok commented Dec 15, 2023

How can I play received (QByteArray) during transferring?
QSharedPointer buffer(new Buffer);

You would need to implement QIODevice and provides bytes from it by
https://doc.qt.io/qt-6/qiodevice.html#read-1

Looks you have already seen this
https://github.com/valbok/QtAVPlayer/blob/master/tests/auto/integration/qavplayer/tst_qavplayer.cpp#L2392

@binarysoft2011
Copy link
Author

binarysoft2011 commented Dec 15, 2023

Thank valbok,
Now player can play from buffer.

@binarysoft2011
Copy link
Author

binarysoft2011 commented Dec 17, 2023

In Windows
player.setInputFormat("dshow");
player.setSource("video=Integrated Camera");
Could not find input format:
so I search my camera device name
player.setInputFormat("dshow");
player.setSource("video=USB2.0 HD UVC WebCam");
it's working.

But in Android.
m_player.setInputFormat("android_camera");
m_player.setSource("0:0");

Could not find input format: "android_camera"
ResourceError : "Invalid argument"
mediaStatusChanged InvalidMedia StoppedState
m_positionTimer stopped due to invalid media

I also check permission
Permission "android.permission.READ_EXTERNAL_STORAGE" already granted!
Permission "android.permission.CAMERA" already granted!
Permission "android.permission.RECORD_AUDIO" already granted!
Camera: "back"
Camera: "front"

@valbok
Copy link
Owner

valbok commented Dec 17, 2023

Could not find input format: "android_camera"
ResourceError : "Invalid argument"

means av_find_input_format failed, make sure that you have android_camera supported

https://ffmpeg.org/doxygen/4.4/android__camera_8c.html

@binarysoft2011
Copy link
Author

binarysoft2011 commented Dec 19, 2023

Get Audio Only(raw data) QByteArray from MP4 file.

I want (extract) audio as QByteArray from video file and send to client or play it.

`QAVDemuxer d;
QSharedPointer file(new QFile("D:/AVPlayer/a.mp4"));
if (!file->open(QIODevice::ReadOnly)) {
qDebug() << "Could not open";
return;
}
QAVIODevice dev(file);
if(d.load("D:/AVPlayer/a.mp4", &dev)) qDebug() << " loaded file";
if(d.currentAudioStreams().isEmpty()) {
qDebug() << " No Audio";
return;
}
if(d.duration() >0) qDebug() << " has duration: " << d.duration();
if(d.seekable()) qDebug() << " has seekable";
if(d.eof()) qDebug() << " has eof";

QAVPacket p;
QAVAudioFrame af;
QByteArray myData;
qint64 iRSize = 0;
while ((p = d.read())) {
    if(d.eof()) { 
		qDebug() << "eof";
		break;
	}
    
	if (p.packet()->stream_index == d.currentAudioStreams().first().index()) {
        QList<QAVFrame> fs;
        d.decode(p, fs);
        if(fs.size() == 1) {
            auto f = fs[0];
            af = f;
            auto data = af.data();
            iRSize += data.size();
            qDebug() << iRSize << " myBuffer->size() " << file->size();
            myData.append(data);
            qDebug() << myData.size() << " myData.size()";
        }
    }
}
if(d.eof()) qDebug() << " eof ";
qDebug() << iRSize << " size " << file->size();`

I think myData is audio raw data. But when I run it program is crack.

In Debug Mode receive size is greater than mp4 file size and program is stop.
........
67097464 size 4769784
67106680 size 4769784
67115896 size 4769784
ASSERT: "!m_thread.isRunning()" in file qqmldebugserver.cpp, line 655

@valbok
Copy link
Owner

valbok commented Dec 19, 2023

I want (extract) audio as QByteArray from video file and send to client or play it.

This exactly what QAVPlayer does, it sends QAVAudioFrame to users, where you can get the data using QAVAudioFrame::data() which returns QByteArray

@binarysoft2011
Copy link
Author

How can I play extract audio qbytearray?

I read a whole file as QByteArray and write to buffer and play buffer.
It's working.

But I extract audio frame.data() and write to buffer and play buffer.
It's not working.

I get myData QByteArray from QAVAudioFrame frame.data()

myBuffer->m_size = myData.size();
myBuffer->open(QIODevice::ReadWrite);
myBuffer->write(myData);
playBuffer(myBuffer);

void playBuffer(QSharedPointer buffer)
{
QFileInfo fileInfo("D:/AVPlayer/tmp.mp3");
QSharedPointer dev(new QAVIODevice(buffer));
m_player.setSource(fileInfo.fileName(), dev);
m_player.play();
}

in Debug
myBuffer->size() 32075177
durationChanged 0
stateChanged PlayingState NoMedia
mediaStatusChanged NoMedia PlayingState
FFmpeg: [mov,mp4,m4a,3gp,3g2,mj2 @ 089C4780] Format mov,mp4,m4a,3gp,3g2,mj2 detected only with low score of 1, misdetection possible!
FFmpeg: [mov,mp4,m4a,3gp,3g2,mj2 @ 089C4780] moov atom not found
ResourceError : "Invalid data found when processing input"
mediaStatusChanged InvalidMedia StoppedState
m_positionTimer stopped due to invalid media
stateChanged StoppedState InvalidMedia

@valbok
Copy link
Owner

valbok commented Dec 20, 2023

QFileInfo fileInfo("D:/AVPlayer/tmp.mp3");
FFmpeg: [mov,mp4,m4a,3gp,3g2,mj2 @ 089C4780] moov atom not found
ResourceError : "Invalid data found when processing input"

I can guess that audio mp3 is wrong extension here, since audio is raw WAV, so rename to tmp.wav

@binarysoft2011
Copy link
Author

binarysoft2011 commented Dec 20, 2023

reading from file (*.mp3 or *.mp4) into buffer then play from buffer.
I use it.
void playBuffer(QSharedPointer buffer)
{
QFileInfo fileInfo("D:/AVPlayer/tmp.mp3");
QSharedPointer dev(new QAVIODevice(buffer));
m_player.setSource(fileInfo.fileName(), dev);
m_player.play();
}
It's working even whatever file name or extension or empty name.

void playBuffer(QSharedPointer buffer)
{
//QFileInfo fileInfo(""); //change to empty file it is working
QSharedPointer dev(new QAVIODevice(buffer));
m_player.setSource("", dev); //remove file and set empty it's working.
m_player.play();
}
I think It play from dev via buffer.

But, i play video and add audio qbytearray into myData during playback.
it's same result not play.
QFileInfo fileInfo1("D:/AVPlayer/0.mp4");
QSharedPointer dev(new QAVIODevice(buffer));
p.setSource(fileInfo1.fileName(), dev);
connect(&p, &QAVPlayer::audioFrame, this, [&](const QAVAudioFrame &frame) {
qDebug() << frame.data().size();
myData.append(frame.data());
pAo.play(frame);
}, Qt::DirectConnection);

result logs are:
myBuffer->size() 32075177

durationChanged 0
stateChanged PlayingState NoMedia
mediaStatusChanged NoMedia PlayingState
FFmpeg: [mov,mp4,m4a,3gp,3g2,mj2 @ 089C4780] Format mov,mp4,m4a,3gp,3g2,mj2 detected only with low score of 1, misdetection possible!
FFmpeg: [mov,mp4,m4a,3gp,3g2,mj2 @ 089C4780] moov atom not found
ResourceError : "Invalid data found when processing input"
mediaStatusChanged InvalidMedia StoppedState
m_positionTimer stopped due to invalid media
stateChanged StoppedState InvalidMedia

@valbok
Copy link
Owner

valbok commented Dec 20, 2023

Sorry, still did not get, does it work?
//remove file and set empty it's working.
p.setSource(fileInfo1.fileName(), dev);
Do you want to play from dev using fileName == D:/AVPlayer/0.mp4

@binarysoft2011
Copy link
Author

binarysoft2011 commented Dec 20, 2023

I want to get audio (QByteArray) from mp4 file and send it to client to play.
So as first step. I test it on same project and not send qbytearray to client yet.

I test it as two ways.

  1. read from mp4 file and add audio QByteArray and test play within same project.
  2. add QByteArray during mp4 file audio playback and test play within same project.
    In all two methods, QByteArray has data.

//write my audio qbytearray to Buffer.
myBuffer->m_size = myData.size();
myBuffer->open(QIODevice::ReadWrite);
myBuffer->write(myData);
playBuffer(); //call below function.

void playBuffer(QSharedPointer<Buffer> buffer)

{
//play from buffer.
QSharedPointer dev(new QAVIODevice(buffer));
m_player.setSource("", dev);
m_player.play();
}

It's not working.
In debug logs are:
myBuffer->size() 32075177
durationChanged 0
stateChanged PlayingState NoMedia
mediaStatusChanged NoMedia PlayingState
FFmpeg: [mov,mp4,m4a,3gp,3g2,mj2 @ 089C4780] Format mov,mp4,m4a,3gp,3g2,mj2 detected only with low score of 1, misdetection possible!
FFmpeg: [mov,mp4,m4a,3gp,3g2,mj2 @ 089C4780] moov atom not found
ResourceError : "Invalid data found when processing input"
mediaStatusChanged InvalidMedia StoppedState
m_positionTimer stopped due to invalid media
stateChanged StoppedState InvalidMedia.

So. I read data (both audio and video) from mp4 and test it.
QFileInfo fileInfo("D:/AVPlayer/0.mp4");
QFile file(fileInfo.absoluteFilePath());
if (!file.open(QIODevice::ReadOnly)) {
qDebug() << "Could not open";
return;
}
QSharedPointer fbuffer(new Buffer);
fbuffer->m_size = file.size();
fbuffer->open(QIODevice::ReadWrite);

QFileInfo fileInfo1("D:/AVPlayer/tmp.mp4"); 
QSharedPointer<QAVIODevice> dev(new QAVIODevice(fbuffer));
m_player.setSource(fileInfo1.fileName(), dev);
m_player.play();

while(!file.atEnd()) {
    auto bytes = file.read(64 * 1024);
    fbuffer->write(bytes);
}
It's working and play video and audio what ever file is D:/AVPlayer/tmp.mp4 or tmp.mp3 or tmp.wav.

@valbok
Copy link
Owner

valbok commented Dec 20, 2023

It's working and play video and audio

Sorry, just forgot, if you would like to play raw pcm data, you should use QAVAudioOutput, without QAVPlayer

@binarysoft2011
Copy link
Author

QAVAudioOutput m_ao;
QAVAudioFrame m_af;

QAVAudioOutput can use QAVAudioFrame.
m_ao(m_af);

How can I convert QByteArray myData to QAVAudioFrame?
audioframe can be get within same project. But I want to send audio data to Client.
So I have to use QByteArray.

@valbok
Copy link
Owner

valbok commented Dec 20, 2023

maybe we could introduce
QAVAudioOutput::play(const char*, format)

or event just use QAudioOutput from qt, why you need a wrapper here

@binarysoft2011
Copy link
Author

m_ao.play(m_af); //m_ao(m_af); missing .play.

QAVAudioOutput::play can be used to play QAVAudioFrame.
It can not be played QByteArray?
Because audio data are send as QByteArray not QAVAudioFrame.

How can I use audio qbytearray in QAVAudioOutput? or
How can I send QAVAudioFrame as any data type to client?

@valbok
Copy link
Owner

valbok commented Dec 20, 2023

QAVAudioFrame provides not only raw data but also its format.

https://doc.qt.io/qt-5/qaudiooutput.html is used to play pcm data, and it is used by QAVAudioOutput. Suggesting to use it directly.

@binarysoft2011
Copy link
Author

binarysoft2011 commented Dec 20, 2023

Thank for your advice and quick replay. I'll try it as your suggestion.

@binarysoft2011
Copy link
Author

binarysoft2011 commented Dec 22, 2023

Audio RawData file or QAVAudioFrame.data() can by played by QAudioOutput.

I get myData QByteArray from QAVAudioFrame frame.data()

QBuffer buffer;
QByteArray audioData = myData;
buffer.setData(audioData);
buffer.open(QIODevice::ReadOnly);
QAudioOutput audio(info, format);
audio.setBufferSize(buffer.size());
audio.start(&buffer);

I can play qbytearray data with QAudioOutput.

But I want to use QtAVPlayer to play rawdata.
QAVAudioOutput::play frame, not qbytearray.

How to play it?

@binarysoft2011
Copy link
Author

I test ffmpeg filters
ffmpeg -i 0.mp3 -filter_complex "asetrate=44100*2,atempo=0.5" -ar 44100 002.mp3
003 audio is changed.

So I test

  1. player.setFilter("asetrate=44100*2,atempo=0.5") or
  2. player.setFilters("asetrate=44100*2;atempo=0.5") or
  3. player.setFilters({"asetrate=44100*2;atempo=0.5"}) or
  4. player.setFilters({"asetrate=44100*2;atempo=0.5"}) and
    player.setInputOptions({{"ar","4100"}});
    audio is not change and shown no error message.

@valbok
Copy link
Owner

valbok commented Dec 27, 2023

Audio RawData file or QAVAudioFrame.data() can by played by QAudioOutput.

I get myData QByteArray from QAVAudioFrame frame.data()

QBuffer buffer; QByteArray audioData = myData; buffer.setData(audioData); buffer.open(QIODevice::ReadOnly); QAudioOutput audio(info, format); audio.setBufferSize(buffer.size()); audio.start(&buffer);

I can play qbytearray data with QAudioOutput.

But I want to use QtAVPlayer to play rawdata. QAVAudioOutput::play frame, not qbytearray.

How to play it?

looks idea to reuse QAVAudioOutput to play not only audio frames is quite nice: #425

To play raw data you must know its format, and QAVPlayer does not actually "play", it parses, demuxes, decodes and synchronizes the streams.

@valbok
Copy link
Owner

valbok commented Dec 27, 2023

-ar 44100 002.mp3

Never tested this and looks it is unsupported for now.

@valbok
Copy link
Owner

valbok commented Jan 20, 2024

maybe we could introduce QAVAudioOutput::play(const char*, format)

or event just use QAudioOutput from qt, why you need a wrapper here

#429

@valbok
Copy link
Owner

valbok commented Jan 22, 2024

Looks like asetrate=44100*2,atempo=0.5 is not needed anymore? Since possible to play raw audio

@binarysoft2011
Copy link
Author

maybe we could introduce QAVAudioOutput::play(const char*, format)
or event just use QAudioOutput from qt, why you need a wrapper here

#429

Yes, I'll do it.
Thanks.

@binarysoft2011
Copy link
Author

Looks like asetrate=44100*2,atempo=0.5 is not needed anymore? Since possible to play raw audio

Yes.

@valbok
Copy link
Owner

valbok commented Jan 26, 2024

If you don't mind, let's close the issue, and feel free to reopen in any case.
again, thank you for contributing.

@valbok valbok closed this as completed Jan 26, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants