DECLARE_CASE_VALUE(EncoderState::kError);
DECLARE_CASE_VALUE(EncoderState::kPreparing);
DECLARE_CASE_VALUE(EncoderState::kUninitialized);
+ DECLARE_CASE_VALUE(EncoderState::kSuspended);
}
return os;
}
return;
}
encoder_ = Encoder(encoder);
+
+ last_state_ = suspend_resume::RegisterClient(this).value_or(
+ suspend_resume::State::RESUMED);
}
TizenVideoEncodeAccelerator::~TizenVideoEncodeAccelerator() {
TIZEN_MEDIA_LOG(INFO) << "Destructing";
CHECK(task_runner_->BelongsToCurrentThread());
+ suspend_resume::UnregisterClient(this);
}
bool TizenVideoEncodeAccelerator::Initialize(
TIZEN_MEDIA_LOG(INFO) << bitrate.ToString();
if (encoder_state_ != EncoderState::kPreparing &&
- encoder_state_ != EncoderState::kEncoding) {
+ encoder_state_ != EncoderState::kEncoding &&
+ encoder_state_ != EncoderState::kSuspended) {
TIZEN_MEDIA_LOG(ERROR)
<< "Cannot update stream bitrate - encoder in a wrong state: "
<< encoder_state_;
delete this;
}
+void TizenVideoEncodeAccelerator::OnStateChange(
+ suspend_resume::State new_state) {
+ last_state_ = new_state;
+
+ switch (new_state) {
+ case suspend_resume::State::RESUMED: {
+ if (!GetTaskRunner()->PostTask(
+ FROM_HERE, base::BindOnce(&TizenVideoEncodeAccelerator::Resume,
+ GetWeakPtr()))) {
+ TIZEN_MEDIA_LOG(ERROR) << "Failed to post |Resume| task";
+ }
+ break;
+ }
+ case suspend_resume::State::PARTIAL:
+ case suspend_resume::State::SUSPENDED: {
+ if (!GetTaskRunner()->PostTask(
+ FROM_HERE, base::BindOnce(&TizenVideoEncodeAccelerator::Suspend,
+ GetWeakPtr()))) {
+ TIZEN_MEDIA_LOG(ERROR) << "Failed to post |Suspend| task";
+ }
+ break;
+ }
+ default: {
+ TIZEN_MEDIA_LOG(WARNING)
+ << "Unrecognized state change in TizenVideoEncodeAccelerator";
+ break;
+ }
+ }
+}
+
void TizenVideoEncodeAccelerator::OnDataFromEncoder(MediaPacketType packet,
uint32_t stream_id) {
TIZEN_MEDIA_LOG(VERBOSE);
CHECK(task_runner_->BelongsToCurrentThread());
}
-void TizenVideoEncodeAccelerator::OnErrorFromEncoder() {
+void TizenVideoEncodeAccelerator::OnErrorFromEncoder(encoder_error_e error) {
TIZEN_MEDIA_LOG(INFO);
CHECK(task_runner_->BelongsToCurrentThread());
+ // Do not report resource conflict when encoder is already suspended. There
+ // might be race between suspend and conflict notifications. After application
+ // resume it should be reclaimed and work normally.
+ if (encoder_state_ == EncoderState::kSuspended &&
+ error == ENCODER_ERROR_RESOURCE_CONFLICT) {
+ return;
+ }
+
ReportErrorToClient();
}
TIZEN_MEDIA_LOG(VERBOSE);
CHECK(task_runner_->BelongsToCurrentThread());
+ // When encoder is suspended it's fine to not return data at all.
+ if (encoder_state_ == EncoderState::kSuspended) {
+ return;
+ }
+
if (encoder_state_ != EncoderState::kEncoding) {
TIZEN_MEDIA_LOG(ERROR) << "Encoding frame failed - wrong encoder state";
return;
}
if (encoder_state_ != EncoderState::kPreparing &&
- encoder_state_ != EncoderState::kEncoding) {
+ encoder_state_ != EncoderState::kEncoding &&
+ encoder_state_ != EncoderState::kSuspended) {
TIZEN_MEDIA_LOG(INFO) << "Cannot close in state = " << encoder_state_;
return;
}
- StopInternal();
+ // When encoder is already suspended, there is no need for stopping or
+ // clearing collections, it's already done.
+ if (encoder_state_ != EncoderState::kSuspended) {
+ StopInternal();
- frames_to_encode_ = {};
- frames_with_data_in_encoder_.clear();
+ frames_to_encode_ = {};
+ frames_with_data_in_encoder_.clear();
+ }
encoder_state_ = EncoderState::kUninitialized;
}
encoder_state_ = EncoderState::kEncoding;
}
+void TizenVideoEncodeAccelerator::Resume() {
+ TIZEN_MEDIA_LOG(INFO) << "Resume called in state: " << encoder_state_;
+ switch (encoder_state_) {
+ case EncoderState::kUninitialized:
+ case EncoderState::kError:
+ case EncoderState::kPreparing:
+ case EncoderState::kEncoding:
+ // Nothing to do.
+ break;
+ case EncoderState::kSuspended:
+ encoder_state_ = EncoderState::kPreparing;
+ StartInternal();
+ if (encoder_state_ != EncoderState::kEncoding) {
+ TIZEN_MEDIA_LOG(ERROR) << "Could not resume encoder";
+ }
+ break;
+ }
+}
+
+void TizenVideoEncodeAccelerator::Suspend() {
+ TIZEN_MEDIA_LOG(INFO) << "Suspend called in state: " << encoder_state_;
+ switch (encoder_state_) {
+ case EncoderState::kUninitialized:
+ case EncoderState::kError:
+ case EncoderState::kPreparing:
+ // Nothing to do.
+ break;
+ case EncoderState::kEncoding:
+ StopInternal();
+ frames_to_encode_ = {};
+ frames_with_data_in_encoder_.clear();
+ encoder_state_ = EncoderState::kSuspended;
+ break;
+ case EncoderState::kSuspended:
+ TIZEN_MEDIA_LOG(WARNING) << "Encoder already suspended";
+ break;
+ }
+}
+
} // namespace media
#include "media/gpu/tizen/tizen_video_encode_accelerator_utils.h"
#include "media/video/h264_parser.h"
#include "media/video/video_encode_accelerator.h"
+#include "services/suspend_resume/public/cpp/suspend_resume.h"
#include "ui/gfx/client_native_pixmap_factory.h"
#include "ui/gfx/range/range.h"
#include "ui/gfx/tbm_surface.h"
using HardwareBuffers = std::vector<std::unique_ptr<gfx::TizenGpuBuffer>>;
-class TizenVideoEncodeAccelerator : public VideoEncodeAccelerator {
+class TizenVideoEncodeAccelerator : public VideoEncodeAccelerator,
+ public suspend_resume::SuspendResumeClient {
public:
TizenVideoEncodeAccelerator();
~TizenVideoEncodeAccelerator() override;
return client_native_pixmap_factory_.get();
}
+ // suspend_resume::SuspendResumeClient implementation.
+ void OnStateChange(suspend_resume::State new_state) override;
+
// Enum representing possible states of platform encoder.
// It allows preventing calling platform encoder in wrong state.
enum class EncoderState {
kError,
kPreparing,
kEncoding,
+ kSuspended,
};
private:
// Callbacks from platform encoder, already dispatched to proper thread.
void OnDataFromEncoder(MediaPacketType packet, uint32_t stream_id);
void OnEncoderBufferStatusChanged(encoder_buffer_status_e status);
- void OnErrorFromEncoder();
+ void OnErrorFromEncoder(encoder_error_e error);
void OnPacketProcessedByEncoder(base::TimeDelta timestamp);
void SchedulePacketSubmit();
const scoped_refptr<VideoFrame>& video_frame,
const MediaFormatType& media_format);
+ void Resume();
+ void Suspend();
+
EncoderState encoder_state_{EncoderState::kUninitialized};
Client* client_{nullptr};
// possible that during processing one error another one will be reported.
bool is_processing_platform_error_{false};
+ // Should always hold last known status of visibility.
+ suspend_resume::State last_state_;
+
// |unique_ptr| with custom deleter used for preventing leak of |encoder_h|
// pointer.
using Encoder =