Skip to content
Snippets Groups Projects
Commit 563e274a authored by Philippe Gorley's avatar Philippe Gorley Committed by Adrien Béraud
Browse files

recorder: ensure format is supported by codecs

VP8 only supports YUV420 frames, and Opus doesn't support every sample
rate, so convert to known supported formats before saving the frames to
file.

Change-Id: I27665437ea95a11ad9a08df76cf666a5f08643b8
parent d6635fa4
No related branches found
No related tags found
No related merge requests found
...@@ -306,17 +306,19 @@ MediaRecorder::setupVideoOutput() ...@@ -306,17 +306,19 @@ MediaRecorder::setupVideoOutput()
const MediaStream& peer = streams_[true][true]; const MediaStream& peer = streams_[true][true];
const MediaStream& local = streams_[true][false]; const MediaStream& local = streams_[true][false];
// vp8 supports only yuv420p
videoFilter_.reset(new MediaFilter);
switch (nbReceivedVideoStreams_) { switch (nbReceivedVideoStreams_) {
case 1: // use a stream with a valid size case 1:
if (peer.width > 0 && peer.height > 0) encoderStream = (peer.width > 0 && peer.height > 0 ? peer : local);
encoderStream = peer; if (videoFilter_->initialize("format=pix_fmts=yuv420p", encoderStream) < 0) {
else if (local.width > 0 && local.height > 0) RING_ERR() << "Failed to initialize video filter";
encoderStream = local;
else
encoderStream.format = -1; // invalidate stream encoderStream.format = -1; // invalidate stream
} else {
encoderStream = videoFilter_->getOutputParams();
}
break; break;
case 2: // overlay local video over peer video case 2: // overlay local video over peer video
videoFilter_.reset(new MediaFilter);
if (videoFilter_->initialize(buildVideoFilter(), if (videoFilter_->initialize(buildVideoFilter(),
std::vector<MediaStream>{peer, local}) < 0) { std::vector<MediaStream>{peer, local}) < 0) {
RING_ERR() << "Failed to initialize video filter"; RING_ERR() << "Failed to initialize video filter";
...@@ -327,9 +329,12 @@ MediaRecorder::setupVideoOutput() ...@@ -327,9 +329,12 @@ MediaRecorder::setupVideoOutput()
break; break;
default: default:
RING_ERR() << "Recording more than 2 video streams is not supported"; RING_ERR() << "Recording more than 2 video streams is not supported";
encoderStream.format = -1; // invalidate stream break;
} }
if (encoderStream.format < 0)
return encoderStream;
RING_DBG() << "Video recorder '" RING_DBG() << "Video recorder '"
<< (encoderStream.name.empty() ? "(null)" : encoderStream.name) << (encoderStream.name.empty() ? "(null)" : encoderStream.name)
<< "' properties: " << "' properties: "
...@@ -372,22 +377,20 @@ MediaRecorder::setupAudioOutput() ...@@ -372,22 +377,20 @@ MediaRecorder::setupAudioOutput()
MediaStream encoderStream; MediaStream encoderStream;
const MediaStream& peer = streams_[false][true]; const MediaStream& peer = streams_[false][true];
const MediaStream& local = streams_[false][false]; const MediaStream& local = streams_[false][false];
std::stringstream aFilter;
// resample to common audio format, so any player can play the file
audioFilter_.reset(new MediaFilter);
switch (nbReceivedAudioStreams_) { switch (nbReceivedAudioStreams_) {
case 1: // use a stream with a valid sample rate and channel count case 1:
if (peer.sampleRate > 0 && peer.nbChannels > 0) encoderStream = (peer.sampleRate > 0 && peer.nbChannels > 0 ? peer : local);
encoderStream = peer; if (audioFilter_->initialize("aresample=osr=48000:ocl=stereo:osf=s16",
else if (local.sampleRate > 0 && local.nbChannels > 0) encoderStream) < 0) {
encoderStream = local; RING_ERR() << "Failed to initialize audio filter";
else
encoderStream.format = -1; // invalidate stream encoderStream.format = -1; // invalidate stream
}
break; break;
case 2: // mix both audio streams case 2: // mix both audio streams
audioFilter_.reset(new MediaFilter); if (audioFilter_->initialize("[a:1][a:2] amix,aresample=osr=48000:ocl=stereo:osf=s16",
// resample to common audio format, so any player can play the file
aFilter << "[a:1] [a:2] amix, aresample=osr=48000:ocl=stereo:osf=s16";
if (audioFilter_->initialize(aFilter.str(),
std::vector<MediaStream>{peer, local}) < 0) { std::vector<MediaStream>{peer, local}) < 0) {
RING_ERR() << "Failed to initialize audio filter"; RING_ERR() << "Failed to initialize audio filter";
encoderStream.format = -1; // invalidate stream encoderStream.format = -1; // invalidate stream
...@@ -401,6 +404,9 @@ MediaRecorder::setupAudioOutput() ...@@ -401,6 +404,9 @@ MediaRecorder::setupAudioOutput()
break; break;
} }
if (encoderStream.format < 0)
return encoderStream;
RING_DBG() << "Audio recorder '" RING_DBG() << "Audio recorder '"
<< (encoderStream.name.empty() ? "(null)" : encoderStream.name) << (encoderStream.name.empty() ? "(null)" : encoderStream.name)
<< "' properties: " << "' properties: "
...@@ -473,7 +479,7 @@ MediaRecorder::process() ...@@ -473,7 +479,7 @@ MediaRecorder::process()
} }
// get filter input name if frame needs filtering // get filter input name if frame needs filtering
std::string inputName; std::string inputName = "default";
if (recframe.isVideo && nbReceivedVideoStreams_ == 2) if (recframe.isVideo && nbReceivedVideoStreams_ == 2)
inputName = (recframe.fromPeer ? "v:main" : "v:overlay"); inputName = (recframe.fromPeer ? "v:main" : "v:overlay");
if (!recframe.isVideo && nbReceivedAudioStreams_ == 2) if (!recframe.isVideo && nbReceivedAudioStreams_ == 2)
...@@ -482,10 +488,6 @@ MediaRecorder::process() ...@@ -482,10 +488,6 @@ MediaRecorder::process()
emptyFilterGraph(); emptyFilterGraph();
if (filter) { if (filter) {
filter->feedInput(input, inputName); filter->feedInput(input, inputName);
} else if (inputName.empty()) { // #nofilters
if (sendToEncoder(input, streamIdx) < 0) {
RING_ERR() << "Failed to encode frame";
}
} }
av_frame_free(&input); av_frame_free(&input);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment