blob: 78d56252bc65e3b732b4f588dd19bc95cee784a2 [file] [log] [blame]
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef SERVICES_MEDIA_FRAMEWORK_FFMPEG_AV_IO_CONTEXT_H_
#define SERVICES_MEDIA_FRAMEWORK_FFMPEG_AV_IO_CONTEXT_H_
#include <condition_variable>
#include <mutex>
#include "services/media/framework/parts/reader.h"
extern "C" {
#include "third_party/ffmpeg/libavformat/avio.h"
}
namespace mojo {
namespace media {
struct AVIOContextDeleter {
void operator()(AVIOContext* context) const;
};
using AvIoContextPtr = std::unique_ptr<AVIOContext, AVIOContextDeleter>;
class AvIoContext {
public:
// Creates an ffmpeg avio_context for a given reader.
static AvIoContextPtr Create(std::shared_ptr<Reader> reader);
};
// 'Opaque' context bound to ffmpeg AVIOContext.
//
// AvIoContextOpaque is instantiated when an AVIOContext is created and is bound
// to the AVIOContext via the 'opaque' field. AvIoContextOpaque's purpose is to
// translate read and seek requests from ffmpeg into terms that make sense for
// the framework. The principal issue is that ffmpeg issues synchronous read and
// seek requests (static Read and Seek below), and the framework exposes these
// capabilities as an asynchronous request (Reader::ReadAt).
//
// AvIoContextOpaque implements synchronous Read requests by issuing an
// asynchronous request and waiting for the callback to be invoked. The wait is
// done using a mutex and a condition_variable. There's no attempt to pump and
// message queues during the wait, so the the ReadAt callback will be on a
// different thread than the synchronous request.
class AvIoContextOpaque {
public:
// Performs a read operation using the signature required for avio.
static int Read(void* opaque, uint8_t* buf, int buf_size);
// Performs a seek operation using the signature required for avio.
static int64_t Seek(void* opaque, int64_t offset, int whence);
~AvIoContextOpaque();
private:
AvIoContextOpaque(std::shared_ptr<Reader> reader);
// Indicates whether the reader can seek
bool can_seek() { return can_seek_; }
// Performs a synchronous read.
int Read(uint8_t* buffer, size_t bytes_to_read);
// Performs a synchronous seek.
int64_t Seek(int64_t offset, int whence);
void WaitForCallback() {
std::unique_lock<std::mutex> lock(mutex_);
while (!callback_happened_) {
condition_variable_.wait(lock);
}
callback_happened_ = false;
}
void CallbackComplete() {
std::unique_lock<std::mutex> lock(mutex_);
DCHECK(!callback_happened_);
callback_happened_ = true;
condition_variable_.notify_all();
}
std::shared_ptr<Reader> reader_;
Result describe_result_;
int64_t size_;
bool can_seek_;
int64_t position_ = 0;
std::mutex mutex_;
std::condition_variable condition_variable_;
bool callback_happened_ = false;
friend class AvIoContext;
};
} // namespace media
} // namespace mojo
#endif // SERVICES_MEDIA_FRAMEWORK_FFMPEG_AV_IO_CONTEXT_H_