ffmpeg audio play / capture done in os x

This commit is contained in:
John Preston 2015-05-30 19:30:47 +03:00
parent 1b11a7feae
commit 1b06fe1220
6 changed files with 98 additions and 48 deletions

View File

@ -30,6 +30,30 @@ extern "C" {
}
#ifdef Q_OS_MAC
extern "C" {
#include <iconv.h>
#undef iconv_open
#undef iconv
#undef iconv_close
iconv_t iconv_open (const char* tocode, const char* fromcode) {
return libiconv_open(tocode, fromcode);
}
size_t iconv (iconv_t cd, char* * inbuf, size_t *inbytesleft, char* * outbuf, size_t *outbytesleft) {
return libiconv(cd, inbuf, inbytesleft, outbuf, outbytesleft);
}
int iconv_close (iconv_t cd) {
return libiconv_close(cd);
}
}
#endif
namespace {
ALCdevice *audioDevice = 0;
ALCcontext *audioContext = 0;
@ -285,48 +309,53 @@ bool AudioPlayer::updateCurrentStarted(int32 pos) {
}
void AudioPlayer::play(AudioData *audio) {
QMutexLocker lock(&playerMutex);
AudioData *stopped = 0;
bool startNow = true;
if (_data[_current].audio != audio) {
switch (_data[_current].state) {
case AudioPlayerStarting:
case AudioPlayerResuming:
case AudioPlayerPlaying:
_data[_current].state = AudioPlayerFinishing;
updateCurrentStarted();
startNow = false;
break;
case AudioPlayerPausing: _data[_current].state = AudioPlayerFinishing; startNow = false; break;
case AudioPlayerPaused: _data[_current].state = AudioPlayerStopped; break;
}
if (_data[_current].audio) {
emit loaderOnCancel(_data[_current].audio);
emit faderOnTimer();
}
}
{
QMutexLocker lock(&playerMutex);
int32 index = 0;
for (; index < AudioVoiceMsgSimultaneously; ++index) {
if (_data[index].audio == audio) {
_current = index;
break;
bool startNow = true;
if (_data[_current].audio != audio) {
switch (_data[_current].state) {
case AudioPlayerStarting:
case AudioPlayerResuming:
case AudioPlayerPlaying:
_data[_current].state = AudioPlayerFinishing;
updateCurrentStarted();
startNow = false;
break;
case AudioPlayerPausing: _data[_current].state = AudioPlayerFinishing; startNow = false; break;
case AudioPlayerPaused: _data[_current].state = AudioPlayerStopped; stopped = _data[_current].audio; break;
}
if (_data[_current].audio) {
emit loaderOnCancel(_data[_current].audio);
emit faderOnTimer();
}
}
int32 index = 0;
for (; index < AudioVoiceMsgSimultaneously; ++index) {
if (_data[index].audio == audio) {
_current = index;
break;
}
}
if (index == AudioVoiceMsgSimultaneously && ++_current >= AudioVoiceMsgSimultaneously) {
_current -= AudioVoiceMsgSimultaneously;
}
_data[_current].audio = audio;
_data[_current].fname = audio->already(true);
_data[_current].data = audio->data;
if (_data[_current].fname.isEmpty() && _data[_current].data.isEmpty()) {
_data[_current].state = AudioPlayerStopped;
onError(audio);
} else if (updateCurrentStarted(0)) {
_data[_current].state = startNow ? AudioPlayerPlaying : AudioPlayerStarting;
_data[_current].loading = true;
emit loaderOnStart(audio);
}
}
if (index == AudioVoiceMsgSimultaneously && ++_current >= AudioVoiceMsgSimultaneously) {
_current -= AudioVoiceMsgSimultaneously;
}
_data[_current].audio = audio;
_data[_current].fname = audio->already(true);
_data[_current].data = audio->data;
if (_data[_current].fname.isEmpty() && _data[_current].data.isEmpty()) {
_data[_current].state = AudioPlayerStopped;
onError(audio);
} else if (updateCurrentStarted(0)) {
_data[_current].state = startNow ? AudioPlayerPlaying : AudioPlayerStarting;
_data[_current].loading = true;
emit loaderOnStart(audio);
}
if (stopped) emit updated(stopped);
}
void AudioPlayer::pauseresume() {
@ -491,7 +520,7 @@ void AudioPlayerFader::onTimer() {
emit audioStopped(m.audio);
}
}
if (pos + m.skipStart - m.position >= AudioCheckPositionDelta) {
if (state == AL_PLAYING && pos + m.skipStart - m.position >= AudioCheckPositionDelta) {
m.position = pos + m.skipStart;
emit playPositionUpdated(m.audio);
}
@ -739,7 +768,7 @@ public:
return false;
}
if (avpkt.stream_index == streamId) {
avcodec_get_frame_defaults(frame);
av_frame_unref(frame);
int got_frame = 0;
if ((res = avcodec_decode_audio4(codecContext, frame, &got_frame, &avpkt)) < 0) {
char err[AV_ERROR_MAX_STRING_SIZE] = { 0 };
@ -800,7 +829,7 @@ public:
private:
int32 freq, fmt, channels;
int32 freq, fmt;
int32 sampleSize, srcRate, dstRate, maxResampleSamples;
uint8_t **dstSamplesData;
int64 len;
@ -1054,6 +1083,8 @@ void AudioPlayerLoaders::onLoad(AudioData *audio) {
if (finished) {
m.skipEnd = 0;
m.duration = m.skipStart + m.samplesCount[0] + m.samplesCount[1] + m.samplesCount[2];
delete j.value();
_loaders.erase(j);
}
m.loading = false;
if (m.state == AudioPlayerResuming || m.state == AudioPlayerPlaying || m.state == AudioPlayerStarting) {
@ -1172,7 +1203,7 @@ void AudioCaptureInner::onStart() {
// Start OpenAL Capture
d->device = alcCaptureOpenDevice(0, AudioVoiceMsgFrequency, AL_FORMAT_MONO16, AudioVoiceMsgBufferSize);
d->device = alcCaptureOpenDevice(0, AudioVoiceMsgFrequency, AL_FORMAT_MONO16, AudioVoiceMsgFrequency / 5);
if (!d->device) {
LOG(("Audio Error: capture device not present!"));
emit error();
@ -1457,7 +1488,7 @@ void AudioCaptureInner::onTimeout() {
}
// Write frames
int32 framesize = d->srcSamples * d->codecContext->channels * sizeof(short), encoded = 0;
while (_captured.size() >= encoded + framesize + fadeSamples * sizeof(short)) {
while (uint32(_captured.size()) >= encoded + framesize + fadeSamples * sizeof(short)) {
writeFrame(encoded, framesize);
encoded += framesize;
}
@ -1527,8 +1558,9 @@ void AudioCaptureInner::writeFrame(int32 offset, int32 framesize) {
// Write audio frame
AVPacket pkt = { 0 }; // data and size must be 0;
AVFrame *frame = avcodec_alloc_frame();
AVPacket pkt;
memset(&pkt, 0, sizeof(pkt)); // data and size must be 0;
AVFrame *frame = av_frame_alloc();
int gotPacket;
av_init_packet(&pkt);
@ -1552,5 +1584,5 @@ void AudioCaptureInner::writeFrame(int32 offset, int32 framesize) {
}
d->fullSamples += samplesCnt;
avcodec_free_frame(&frame);
av_frame_free(&frame);
}

View File

@ -35,6 +35,9 @@ enum AudioPlayerState {
AudioPlayerResuming,
};
class AudioPlayerFader;
class AudioPlayerLoaders;
class AudioPlayer : public QObject {
Q_OBJECT
@ -104,6 +107,8 @@ private:
};
class AudioCaptureInner;
class AudioCapture : public QObject {
Q_OBJECT
@ -199,6 +204,8 @@ private:
};
struct AudioCapturePrivate;
class AudioCaptureInner : public QObject {
Q_OBJECT
@ -225,7 +232,6 @@ private:
void writeFrame(int32 offset, int32 framesize);
friend struct AudioCapturePrivate;
AudioCapturePrivate *d;
QTimer _timer;
QByteArray _captured;

View File

@ -3031,6 +3031,7 @@ void HistoryWidget::stopRecording(bool send) {
_recordingAnim.stop();
_recording = false;
_recordingSamples = 0;
updateControlsVisibility();
activate();

View File

@ -49,7 +49,7 @@ typedef QList<ToPrepareMedia> ToPrepareMedias;
typedef QMap<int32, QByteArray> LocalFileParts;
struct ReadyLocalMedia {
ReadyLocalMedia(ToPrepareMediaType type, const QString &file, const QString &filename, int32 filesize, const QByteArray &data, const uint64 &id, const uint64 &thumbId, const QString &thumbExt, const PeerId &peer, const MTPPhoto &photo, const MTPAudio &audio, const PreparedPhotoThumbs &photoThumbs, const MTPDocument &document, const QByteArray &jpeg, bool ctrlShiftEnter, MsgId replyTo) :
replyTo(replyTo), type(type), file(file), filename(filename), filesize(filesize), data(data), thumbExt(thumbExt), id(id), thumbId(thumbId), peer(peer), photo(photo), document(document), photoThumbs(photoThumbs), audio(audio), ctrlShiftEnter(ctrlShiftEnter) {
replyTo(replyTo), type(type), file(file), filename(filename), filesize(filesize), data(data), thumbExt(thumbExt), id(id), thumbId(thumbId), peer(peer), photo(photo), document(document), audio(audio), photoThumbs(photoThumbs), ctrlShiftEnter(ctrlShiftEnter) {
if (!jpeg.isEmpty()) {
int32 size = jpeg.size();
for (int32 i = 0, part = 0; i < size; i += UploadPartSize, ++part) {

View File

@ -1863,6 +1863,11 @@
/usr/local/lib/libmpg123.a,
/usr/local/lib/libfaad.a,
/usr/local/lib/libmp4ff.a,
/usr/local/lib/libavcodec.a,
/usr/local/lib/libavformat.a,
/usr/local/lib/libswresample.a,
/usr/local/lib/libavutil.a,
/usr/local/lib/libiconv.a,
"../../Libraries/openssl-xcode/libcrypto.a",
);
PRODUCT_NAME = Telegram;
@ -2010,6 +2015,11 @@
/usr/local/lib/libmpg123.a,
/usr/local/lib/libfaad.a,
/usr/local/lib/libmp4ff.a,
/usr/local/lib/libavcodec.a,
/usr/local/lib/libavformat.a,
/usr/local/lib/libswresample.a,
/usr/local/lib/libavutil.a,
/usr/local/lib/libiconv.a,
"../../Libraries/openssl-xcode/libcrypto.a",
);
PRODUCT_NAME = Telegram;

View File

@ -131,6 +131,7 @@ GeneratedFiles/Debug/moc_application.cpp: ../../Libraries/QtStatic/qtbase/includ
/usr/local/Qt-5.4.0/bin/moc $(DEFINES) -D__APPLE__ -D__GNUC__=4 -I/usr/local/Qt-5.4.0/mkspecs/macx-clang -I. -I/usr/local/Qt-5.4.0/include/QtGui/5.4.0/QtGui -I/usr/local/Qt-5.4.0/include/QtCore/5.4.0/QtCore -I/usr/local/Qt-5.4.0/include -I./SourceFiles -I./GeneratedFiles -I../../Libraries/lzma/C -I../../Libraries/libexif-0.6.20 -I/usr/local/Qt-5.4.0/include -I/usr/local/Qt-5.4.0/include/QtMultimedia -I/usr/local/Qt-5.4.0/include/QtWidgets -I/usr/local/Qt-5.4.0/include/QtNetwork -I/usr/local/Qt-5.4.0/include/QtGui -I/usr/local/Qt-5.4.0/include/QtCore -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/include/c++/4.2.1 -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/include/c++/4.2.1/backward -I/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/5.1/include -I/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include -I/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk/usr/include SourceFiles/application.h -o GeneratedFiles/Debug/moc_application.cpp
GeneratedFiles/Debug/moc_audio.cpp: SourceFiles/types.h \
SourceFiles/audio.h \
../../Libraries/QtStatic/qtbase/include/QtCore/QReadWriteLock \
SourceFiles/logs.h \
../../Libraries/QtStatic/qtbase/include/QtCore/QTimer \