Loading media/libmediatranscoding/transcoder/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ cc_library_shared { "MediaSampleQueue.cpp", "MediaSampleReaderNDK.cpp", "MediaTrackTranscoder.cpp", "PassthroughTrackTranscoder.cpp", "VideoTrackTranscoder.cpp", ], Loading media/libmediatranscoding/transcoder/PassthroughTrackTranscoder.cpp 0 → 100644 +156 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ // #define LOG_NDEBUG 0 #define LOG_TAG "PassthroughTrackTranscoder" #include <android-base/logging.h> #include <media/PassthroughTrackTranscoder.h> namespace android { PassthroughTrackTranscoder::BufferPool::~BufferPool() { for (auto it = mAddressSizeMap.begin(); it != mAddressSizeMap.end(); ++it) { delete[] it->first; } } uint8_t* PassthroughTrackTranscoder::BufferPool::getBufferWithSize(size_t minimumBufferSize) NO_THREAD_SAFETY_ANALYSIS { std::unique_lock lock(mMutex); // Wait if maximum number of buffers are allocated but none are free. while (mAddressSizeMap.size() >= mMaxBufferCount && mFreeBufferMap.empty() && !mAborted) { mCondition.wait(lock); } if (mAborted) { return nullptr; } // Check if the free list contains a large enough buffer. auto it = mFreeBufferMap.lower_bound(minimumBufferSize); if (it != mFreeBufferMap.end()) { mFreeBufferMap.erase(it); return it->second; } // Allocate a new buffer. uint8_t* buffer = new (std::nothrow) uint8_t[minimumBufferSize]; if (buffer == nullptr) { LOG(ERROR) << "Unable to allocate new buffer of size: " << minimumBufferSize; return nullptr; } // If the maximum buffer count is reached, remove an existing free buffer. if (mAddressSizeMap.size() >= mMaxBufferCount) { auto it = mFreeBufferMap.begin(); mFreeBufferMap.erase(it); mAddressSizeMap.erase(it->second); delete[] it->second; } // Add the buffer to the tracking set. mAddressSizeMap.emplace(buffer, minimumBufferSize); return buffer; } void PassthroughTrackTranscoder::BufferPool::returnBuffer(uint8_t* buffer) { std::scoped_lock lock(mMutex); if (buffer == nullptr || mAddressSizeMap.find(buffer) == mAddressSizeMap.end()) { LOG(WARNING) << "Ignoring untracked buffer " << buffer; return; } mFreeBufferMap.emplace(mAddressSizeMap[buffer], buffer); mCondition.notify_one(); } void PassthroughTrackTranscoder::BufferPool::abort() { std::scoped_lock lock(mMutex); mAborted = true; mCondition.notify_all(); } media_status_t PassthroughTrackTranscoder::configureDestinationFormat( const std::shared_ptr<AMediaFormat>& destinationFormat __unused) { // Called by MediaTrackTranscoder. Passthrough doesn't care about destination so just return ok. return AMEDIA_OK; } media_status_t PassthroughTrackTranscoder::runTranscodeLoop() { MediaSampleInfo info; std::shared_ptr<MediaSample> sample; MediaSample::OnSampleReleasedCallback bufferReleaseCallback = [bufferPool = mBufferPool](MediaSample* sample) { bufferPool->returnBuffer(const_cast<uint8_t*>(sample->buffer)); }; // Move samples until EOS is reached or transcoding is stopped. while (!mStopRequested && !mEosFromSource) { media_status_t status = mMediaSampleReader->getSampleInfoForTrack(mTrackIndex, &info); if (status == AMEDIA_OK) { uint8_t* buffer = mBufferPool->getBufferWithSize(info.size); if (buffer == nullptr) { if (mStopRequested) { break; } LOG(ERROR) << "Unable to get buffer from pool"; return AMEDIA_ERROR_IO; // TODO: Custom error codes? } sample = MediaSample::createWithReleaseCallback( buffer, 0 /* offset */, 0 /* bufferId */, bufferReleaseCallback); status = mMediaSampleReader->readSampleDataForTrack(mTrackIndex, buffer, info.size); if (status != AMEDIA_OK) { LOG(ERROR) << "Unable to read next sample data. Aborting transcode."; return status; } } else if (status == AMEDIA_ERROR_END_OF_STREAM) { sample = std::make_shared<MediaSample>(); mEosFromSource = true; } else { LOG(ERROR) << "Unable to get next sample info. Aborting transcode."; return status; } sample->info = info; if (mOutputQueue.enqueue(sample)) { LOG(ERROR) << "Output queue aborted"; return AMEDIA_ERROR_IO; } mMediaSampleReader->advanceTrack(mTrackIndex); } if (mStopRequested && !mEosFromSource) { return AMEDIA_ERROR_UNKNOWN; // TODO: Custom error codes? } return AMEDIA_OK; } void PassthroughTrackTranscoder::abortTranscodeLoop() { mStopRequested = true; mBufferPool->abort(); } } // namespace android media/libmediatranscoding/transcoder/VideoTrackTranscoder.cpp +24 −26 Original line number Diff line number Diff line Loading @@ -71,7 +71,7 @@ struct AsyncCodecCallbackDispatch { transcoder->mCodecMessageQueue.push([transcoder, index, codec, bufferInfo] { if (codec == transcoder->mDecoder) { transcoder->transferBuffer(index, bufferInfo); } else if (codec == transcoder->mEncoder) { } else if (codec == transcoder->mEncoder.get()) { transcoder->dequeueOutputSample(index, bufferInfo); } }); Loading Loading @@ -102,10 +102,6 @@ VideoTrackTranscoder::~VideoTrackTranscoder() { AMediaCodec_delete(mDecoder); } if (mEncoder != nullptr) { AMediaCodec_delete(mEncoder); } if (mSurface != nullptr) { ANativeWindow_release(mSurface); } Loading @@ -132,20 +128,22 @@ media_status_t VideoTrackTranscoder::configureDestinationFormat( return AMEDIA_ERROR_INVALID_PARAMETER; } mEncoder = AMediaCodec_createEncoderByType(destinationMime); if (mEncoder == nullptr) { AMediaCodec* encoder = AMediaCodec_createEncoderByType(destinationMime); if (encoder == nullptr) { LOG(ERROR) << "Unable to create encoder for type " << destinationMime; return AMEDIA_ERROR_UNSUPPORTED; } mEncoder = std::shared_ptr<AMediaCodec>(encoder, std::bind(AMediaCodec_delete, std::placeholders::_1)); status = AMediaCodec_configure(mEncoder, mDestinationFormat.get(), NULL /* surface */, status = AMediaCodec_configure(mEncoder.get(), mDestinationFormat.get(), NULL /* surface */, NULL /* crypto */, AMEDIACODEC_CONFIGURE_FLAG_ENCODE); if (status != AMEDIA_OK) { LOG(ERROR) << "Unable to configure video encoder: " << status; return status; } status = AMediaCodec_createInputSurface(mEncoder, &mSurface); status = AMediaCodec_createInputSurface(mEncoder.get(), &mSurface); if (status != AMEDIA_OK) { LOG(ERROR) << "Unable to create an encoder input surface: %d" << status; return status; Loading Loading @@ -185,7 +183,7 @@ media_status_t VideoTrackTranscoder::configureDestinationFormat( return status; } status = AMediaCodec_setAsyncNotifyCallback(mEncoder, asyncCodecCallbacks, this); status = AMediaCodec_setAsyncNotifyCallback(mEncoder.get(), asyncCodecCallbacks, this); if (status != AMEDIA_OK) { LOG(ERROR) << "Unable to set encoder to async mode: " << status; return status; Loading @@ -197,7 +195,7 @@ media_status_t VideoTrackTranscoder::configureDestinationFormat( void VideoTrackTranscoder::enqueueInputSample(int32_t bufferIndex) { media_status_t status = AMEDIA_OK; if (mEOSFromSource) { if (mEosFromSource) { return; } Loading Loading @@ -233,7 +231,7 @@ void VideoTrackTranscoder::enqueueInputSample(int32_t bufferIndex) { mMediaSampleReader->advanceTrack(mTrackIndex); } else { LOG(DEBUG) << "EOS from source."; mEOSFromSource = true; mEosFromSource = true; } status = AMediaCodec_queueInputBuffer(mDecoder, bufferIndex, 0, mSampleInfo.size, Loading @@ -253,7 +251,7 @@ void VideoTrackTranscoder::transferBuffer(int32_t bufferIndex, AMediaCodecBuffer if (bufferInfo.flags & AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM) { LOG(DEBUG) << "EOS from decoder."; media_status_t status = AMediaCodec_signalEndOfInputStream(mEncoder); media_status_t status = AMediaCodec_signalEndOfInputStream(mEncoder.get()); if (status != AMEDIA_OK) { LOG(ERROR) << "SignalEOS on encoder returned error: " << status; mStatus = status; Loading @@ -265,11 +263,15 @@ void VideoTrackTranscoder::dequeueOutputSample(int32_t bufferIndex, AMediaCodecBufferInfo bufferInfo) { if (bufferIndex >= 0) { size_t sampleSize = 0; uint8_t* buffer = AMediaCodec_getOutputBuffer(mEncoder, bufferIndex, &sampleSize); uint8_t* buffer = AMediaCodec_getOutputBuffer(mEncoder.get(), bufferIndex, &sampleSize); MediaSample::OnSampleReleasedCallback bufferReleaseCallback = [encoder = mEncoder]( MediaSample* sample) { AMediaCodec_releaseOutputBuffer(encoder.get(), sample->bufferId, false /* render */); }; std::shared_ptr<MediaSample> sample = MediaSample::createWithReleaseCallback( buffer, bufferInfo.offset, bufferIndex, std::bind(&VideoTrackTranscoder::releaseOutputSample, this, std::placeholders::_1)); buffer, bufferInfo.offset, bufferIndex, bufferReleaseCallback); sample->info.size = bufferInfo.size; sample->info.flags = bufferInfo.flags; sample->info.presentationTimeUs = bufferInfo.presentationTimeUs; Loading @@ -281,18 +283,14 @@ void VideoTrackTranscoder::dequeueOutputSample(int32_t bufferIndex, return; } } else if (bufferIndex == AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED) { AMediaFormat* newFormat = AMediaCodec_getOutputFormat(mEncoder); AMediaFormat* newFormat = AMediaCodec_getOutputFormat(mEncoder.get()); LOG(DEBUG) << "Encoder output format changed: " << AMediaFormat_toString(newFormat); } if (bufferInfo.flags & AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM) { LOG(DEBUG) << "EOS from encoder."; mEOSFromEncoder = true; } mEosFromEncoder = true; } void VideoTrackTranscoder::releaseOutputSample(MediaSample* sample) { AMediaCodec_releaseOutputBuffer(mEncoder, sample->bufferId, false /* render */); } media_status_t VideoTrackTranscoder::runTranscodeLoop() { Loading @@ -304,7 +302,7 @@ media_status_t VideoTrackTranscoder::runTranscodeLoop() { return status; } status = AMediaCodec_start(mEncoder); status = AMediaCodec_start(mEncoder.get()); if (status != AMEDIA_OK) { LOG(ERROR) << "Unable to start video encoder: " << status; AMediaCodec_stop(mDecoder); Loading @@ -312,18 +310,18 @@ media_status_t VideoTrackTranscoder::runTranscodeLoop() { } // Process codec events until EOS is reached, transcoding is stopped or an error occurs. while (!mStopRequested && !mEOSFromEncoder && mStatus == AMEDIA_OK) { while (!mStopRequested && !mEosFromEncoder && mStatus == AMEDIA_OK) { std::function<void()> message = mCodecMessageQueue.pop(); message(); } // Return error if transcoding was stopped before it finished. if (mStopRequested && !mEOSFromEncoder && mStatus == AMEDIA_OK) { if (mStopRequested && !mEosFromEncoder && mStatus == AMEDIA_OK) { mStatus = AMEDIA_ERROR_UNKNOWN; // TODO: Define custom error codes? } AMediaCodec_stop(mDecoder); AMediaCodec_stop(mEncoder); AMediaCodec_stop(mEncoder.get()); return mStatus; } Loading media/libmediatranscoding/transcoder/include/media/MediaSample.h +2 −0 Original line number Diff line number Diff line Loading @@ -104,6 +104,8 @@ struct MediaSample { /** Media sample information. */ MediaSampleInfo info; MediaSample() = default; private: MediaSample(uint8_t* buffer, size_t dataOffset, uint32_t bufferId, OnSampleReleasedCallback releaseCallback) Loading media/libmediatranscoding/transcoder/include/media/MediaTrackTranscoder.h +5 −1 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ #include <functional> #include <memory> #include <mutex> #include <thread> namespace android { Loading Loading @@ -94,7 +95,10 @@ public: */ bool stop(); /** Sample output queue. */ /** * Sample output queue. * TODO(b/155918341) Move to protected. */ MediaSampleQueue mOutputQueue = {}; protected: Loading Loading
media/libmediatranscoding/transcoder/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ cc_library_shared { "MediaSampleQueue.cpp", "MediaSampleReaderNDK.cpp", "MediaTrackTranscoder.cpp", "PassthroughTrackTranscoder.cpp", "VideoTrackTranscoder.cpp", ], Loading
media/libmediatranscoding/transcoder/PassthroughTrackTranscoder.cpp 0 → 100644 +156 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ // #define LOG_NDEBUG 0 #define LOG_TAG "PassthroughTrackTranscoder" #include <android-base/logging.h> #include <media/PassthroughTrackTranscoder.h> namespace android { PassthroughTrackTranscoder::BufferPool::~BufferPool() { for (auto it = mAddressSizeMap.begin(); it != mAddressSizeMap.end(); ++it) { delete[] it->first; } } uint8_t* PassthroughTrackTranscoder::BufferPool::getBufferWithSize(size_t minimumBufferSize) NO_THREAD_SAFETY_ANALYSIS { std::unique_lock lock(mMutex); // Wait if maximum number of buffers are allocated but none are free. while (mAddressSizeMap.size() >= mMaxBufferCount && mFreeBufferMap.empty() && !mAborted) { mCondition.wait(lock); } if (mAborted) { return nullptr; } // Check if the free list contains a large enough buffer. auto it = mFreeBufferMap.lower_bound(minimumBufferSize); if (it != mFreeBufferMap.end()) { mFreeBufferMap.erase(it); return it->second; } // Allocate a new buffer. uint8_t* buffer = new (std::nothrow) uint8_t[minimumBufferSize]; if (buffer == nullptr) { LOG(ERROR) << "Unable to allocate new buffer of size: " << minimumBufferSize; return nullptr; } // If the maximum buffer count is reached, remove an existing free buffer. if (mAddressSizeMap.size() >= mMaxBufferCount) { auto it = mFreeBufferMap.begin(); mFreeBufferMap.erase(it); mAddressSizeMap.erase(it->second); delete[] it->second; } // Add the buffer to the tracking set. mAddressSizeMap.emplace(buffer, minimumBufferSize); return buffer; } void PassthroughTrackTranscoder::BufferPool::returnBuffer(uint8_t* buffer) { std::scoped_lock lock(mMutex); if (buffer == nullptr || mAddressSizeMap.find(buffer) == mAddressSizeMap.end()) { LOG(WARNING) << "Ignoring untracked buffer " << buffer; return; } mFreeBufferMap.emplace(mAddressSizeMap[buffer], buffer); mCondition.notify_one(); } void PassthroughTrackTranscoder::BufferPool::abort() { std::scoped_lock lock(mMutex); mAborted = true; mCondition.notify_all(); } media_status_t PassthroughTrackTranscoder::configureDestinationFormat( const std::shared_ptr<AMediaFormat>& destinationFormat __unused) { // Called by MediaTrackTranscoder. Passthrough doesn't care about destination so just return ok. return AMEDIA_OK; } media_status_t PassthroughTrackTranscoder::runTranscodeLoop() { MediaSampleInfo info; std::shared_ptr<MediaSample> sample; MediaSample::OnSampleReleasedCallback bufferReleaseCallback = [bufferPool = mBufferPool](MediaSample* sample) { bufferPool->returnBuffer(const_cast<uint8_t*>(sample->buffer)); }; // Move samples until EOS is reached or transcoding is stopped. while (!mStopRequested && !mEosFromSource) { media_status_t status = mMediaSampleReader->getSampleInfoForTrack(mTrackIndex, &info); if (status == AMEDIA_OK) { uint8_t* buffer = mBufferPool->getBufferWithSize(info.size); if (buffer == nullptr) { if (mStopRequested) { break; } LOG(ERROR) << "Unable to get buffer from pool"; return AMEDIA_ERROR_IO; // TODO: Custom error codes? } sample = MediaSample::createWithReleaseCallback( buffer, 0 /* offset */, 0 /* bufferId */, bufferReleaseCallback); status = mMediaSampleReader->readSampleDataForTrack(mTrackIndex, buffer, info.size); if (status != AMEDIA_OK) { LOG(ERROR) << "Unable to read next sample data. Aborting transcode."; return status; } } else if (status == AMEDIA_ERROR_END_OF_STREAM) { sample = std::make_shared<MediaSample>(); mEosFromSource = true; } else { LOG(ERROR) << "Unable to get next sample info. Aborting transcode."; return status; } sample->info = info; if (mOutputQueue.enqueue(sample)) { LOG(ERROR) << "Output queue aborted"; return AMEDIA_ERROR_IO; } mMediaSampleReader->advanceTrack(mTrackIndex); } if (mStopRequested && !mEosFromSource) { return AMEDIA_ERROR_UNKNOWN; // TODO: Custom error codes? } return AMEDIA_OK; } void PassthroughTrackTranscoder::abortTranscodeLoop() { mStopRequested = true; mBufferPool->abort(); } } // namespace android
media/libmediatranscoding/transcoder/VideoTrackTranscoder.cpp +24 −26 Original line number Diff line number Diff line Loading @@ -71,7 +71,7 @@ struct AsyncCodecCallbackDispatch { transcoder->mCodecMessageQueue.push([transcoder, index, codec, bufferInfo] { if (codec == transcoder->mDecoder) { transcoder->transferBuffer(index, bufferInfo); } else if (codec == transcoder->mEncoder) { } else if (codec == transcoder->mEncoder.get()) { transcoder->dequeueOutputSample(index, bufferInfo); } }); Loading Loading @@ -102,10 +102,6 @@ VideoTrackTranscoder::~VideoTrackTranscoder() { AMediaCodec_delete(mDecoder); } if (mEncoder != nullptr) { AMediaCodec_delete(mEncoder); } if (mSurface != nullptr) { ANativeWindow_release(mSurface); } Loading @@ -132,20 +128,22 @@ media_status_t VideoTrackTranscoder::configureDestinationFormat( return AMEDIA_ERROR_INVALID_PARAMETER; } mEncoder = AMediaCodec_createEncoderByType(destinationMime); if (mEncoder == nullptr) { AMediaCodec* encoder = AMediaCodec_createEncoderByType(destinationMime); if (encoder == nullptr) { LOG(ERROR) << "Unable to create encoder for type " << destinationMime; return AMEDIA_ERROR_UNSUPPORTED; } mEncoder = std::shared_ptr<AMediaCodec>(encoder, std::bind(AMediaCodec_delete, std::placeholders::_1)); status = AMediaCodec_configure(mEncoder, mDestinationFormat.get(), NULL /* surface */, status = AMediaCodec_configure(mEncoder.get(), mDestinationFormat.get(), NULL /* surface */, NULL /* crypto */, AMEDIACODEC_CONFIGURE_FLAG_ENCODE); if (status != AMEDIA_OK) { LOG(ERROR) << "Unable to configure video encoder: " << status; return status; } status = AMediaCodec_createInputSurface(mEncoder, &mSurface); status = AMediaCodec_createInputSurface(mEncoder.get(), &mSurface); if (status != AMEDIA_OK) { LOG(ERROR) << "Unable to create an encoder input surface: %d" << status; return status; Loading Loading @@ -185,7 +183,7 @@ media_status_t VideoTrackTranscoder::configureDestinationFormat( return status; } status = AMediaCodec_setAsyncNotifyCallback(mEncoder, asyncCodecCallbacks, this); status = AMediaCodec_setAsyncNotifyCallback(mEncoder.get(), asyncCodecCallbacks, this); if (status != AMEDIA_OK) { LOG(ERROR) << "Unable to set encoder to async mode: " << status; return status; Loading @@ -197,7 +195,7 @@ media_status_t VideoTrackTranscoder::configureDestinationFormat( void VideoTrackTranscoder::enqueueInputSample(int32_t bufferIndex) { media_status_t status = AMEDIA_OK; if (mEOSFromSource) { if (mEosFromSource) { return; } Loading Loading @@ -233,7 +231,7 @@ void VideoTrackTranscoder::enqueueInputSample(int32_t bufferIndex) { mMediaSampleReader->advanceTrack(mTrackIndex); } else { LOG(DEBUG) << "EOS from source."; mEOSFromSource = true; mEosFromSource = true; } status = AMediaCodec_queueInputBuffer(mDecoder, bufferIndex, 0, mSampleInfo.size, Loading @@ -253,7 +251,7 @@ void VideoTrackTranscoder::transferBuffer(int32_t bufferIndex, AMediaCodecBuffer if (bufferInfo.flags & AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM) { LOG(DEBUG) << "EOS from decoder."; media_status_t status = AMediaCodec_signalEndOfInputStream(mEncoder); media_status_t status = AMediaCodec_signalEndOfInputStream(mEncoder.get()); if (status != AMEDIA_OK) { LOG(ERROR) << "SignalEOS on encoder returned error: " << status; mStatus = status; Loading @@ -265,11 +263,15 @@ void VideoTrackTranscoder::dequeueOutputSample(int32_t bufferIndex, AMediaCodecBufferInfo bufferInfo) { if (bufferIndex >= 0) { size_t sampleSize = 0; uint8_t* buffer = AMediaCodec_getOutputBuffer(mEncoder, bufferIndex, &sampleSize); uint8_t* buffer = AMediaCodec_getOutputBuffer(mEncoder.get(), bufferIndex, &sampleSize); MediaSample::OnSampleReleasedCallback bufferReleaseCallback = [encoder = mEncoder]( MediaSample* sample) { AMediaCodec_releaseOutputBuffer(encoder.get(), sample->bufferId, false /* render */); }; std::shared_ptr<MediaSample> sample = MediaSample::createWithReleaseCallback( buffer, bufferInfo.offset, bufferIndex, std::bind(&VideoTrackTranscoder::releaseOutputSample, this, std::placeholders::_1)); buffer, bufferInfo.offset, bufferIndex, bufferReleaseCallback); sample->info.size = bufferInfo.size; sample->info.flags = bufferInfo.flags; sample->info.presentationTimeUs = bufferInfo.presentationTimeUs; Loading @@ -281,18 +283,14 @@ void VideoTrackTranscoder::dequeueOutputSample(int32_t bufferIndex, return; } } else if (bufferIndex == AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED) { AMediaFormat* newFormat = AMediaCodec_getOutputFormat(mEncoder); AMediaFormat* newFormat = AMediaCodec_getOutputFormat(mEncoder.get()); LOG(DEBUG) << "Encoder output format changed: " << AMediaFormat_toString(newFormat); } if (bufferInfo.flags & AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM) { LOG(DEBUG) << "EOS from encoder."; mEOSFromEncoder = true; } mEosFromEncoder = true; } void VideoTrackTranscoder::releaseOutputSample(MediaSample* sample) { AMediaCodec_releaseOutputBuffer(mEncoder, sample->bufferId, false /* render */); } media_status_t VideoTrackTranscoder::runTranscodeLoop() { Loading @@ -304,7 +302,7 @@ media_status_t VideoTrackTranscoder::runTranscodeLoop() { return status; } status = AMediaCodec_start(mEncoder); status = AMediaCodec_start(mEncoder.get()); if (status != AMEDIA_OK) { LOG(ERROR) << "Unable to start video encoder: " << status; AMediaCodec_stop(mDecoder); Loading @@ -312,18 +310,18 @@ media_status_t VideoTrackTranscoder::runTranscodeLoop() { } // Process codec events until EOS is reached, transcoding is stopped or an error occurs. while (!mStopRequested && !mEOSFromEncoder && mStatus == AMEDIA_OK) { while (!mStopRequested && !mEosFromEncoder && mStatus == AMEDIA_OK) { std::function<void()> message = mCodecMessageQueue.pop(); message(); } // Return error if transcoding was stopped before it finished. if (mStopRequested && !mEOSFromEncoder && mStatus == AMEDIA_OK) { if (mStopRequested && !mEosFromEncoder && mStatus == AMEDIA_OK) { mStatus = AMEDIA_ERROR_UNKNOWN; // TODO: Define custom error codes? } AMediaCodec_stop(mDecoder); AMediaCodec_stop(mEncoder); AMediaCodec_stop(mEncoder.get()); return mStatus; } Loading
media/libmediatranscoding/transcoder/include/media/MediaSample.h +2 −0 Original line number Diff line number Diff line Loading @@ -104,6 +104,8 @@ struct MediaSample { /** Media sample information. */ MediaSampleInfo info; MediaSample() = default; private: MediaSample(uint8_t* buffer, size_t dataOffset, uint32_t bufferId, OnSampleReleasedCallback releaseCallback) Loading
media/libmediatranscoding/transcoder/include/media/MediaTrackTranscoder.h +5 −1 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ #include <functional> #include <memory> #include <mutex> #include <thread> namespace android { Loading Loading @@ -94,7 +95,10 @@ public: */ bool stop(); /** Sample output queue. */ /** * Sample output queue. * TODO(b/155918341) Move to protected. */ MediaSampleQueue mOutputQueue = {}; protected: Loading