Skip to content

Commit

Permalink
Refactor the constructors of pointer wrappers
Browse files Browse the repository at this point in the history
This commit refactor the constructor of wrapper classes so that
wrapper classes are only responsible for deallocation of underlying
FFmpeg custom structures.

The responsibility of custom initialization is moved to helper functions.

Context:

FFmpeg API uses bunch of raw pointers, which require dedicated allocater
and deallcoator. In torchaudio we wrap these pointers with
`std::unique_ptr<>` to adopt RAII semantics.

Currently all of the customization logics required for `Streamer` are
handled by the constructor of wrapper class. Like the following;

```
AVFormatContextPtr(
      const std::string& src,
      const std::string& device,
      const std::map<std::string, std::string>& option);
```

This constrcutor allocates the raw `AVFormatContext*` pointer,
while initializing it with the given option, then it parses the
input media.

As we consider the write/encode features, which require different way
of initializing the `AVFormatContext*`, making it the responsibility
of constructors of `AVFormatContextPtr` reduce the flexibility.

Thus this commit moves the customization to helper factory function.

- `AVFormatContextPtr(...)` -> `get_output_format_context(...)`
- `AVCodecContextPtr(...)` -> `get_decode_context(...)`
  • Loading branch information
mthrok committed May 8, 2022
1 parent b7624c6 commit 899e679
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 39 deletions.
4 changes: 3 additions & 1 deletion torchaudio/csrc/ffmpeg/decoder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ Decoder::Decoder(
AVCodecParameters* pParam,
const std::string& decoder_name,
const std::map<std::string, std::string>& decoder_option)
: pCodecContext(pParam, decoder_name, decoder_option) {}
: pCodecContext(get_decode_context(pParam->codec_id, decoder_name)) {
init_codec_context(pCodecContext, pParam, decoder_name, decoder_option);
}

int Decoder::process_packet(AVPacket* pPacket) {
return avcodec_send_packet(pCodecContext, pPacket);
Expand Down
50 changes: 21 additions & 29 deletions torchaudio/csrc/ffmpeg/ffmpeg.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,9 @@ std::string join(std::vector<std::string> vars) {
#define AVINPUT_FORMAT_CONST
#endif

AVFormatContext* get_format_context(
} // namespace

AVFormatContextPtr get_input_format_context(
const std::string& src,
const std::string& device,
const std::map<std::string, std::string>& option) {
Expand All @@ -82,19 +84,11 @@ AVFormatContext* get_format_context(
throw std::runtime_error(
"Failed to open the input \"" + src + "\" (" + av_err2string(ret) +
").");
return pFormat;
return AVFormatContextPtr(pFormat);
}
} // namespace

AVFormatContextPtr::AVFormatContextPtr(
const std::string& src,
const std::string& device,
const std::map<std::string, std::string>& option)
: Wrapper<AVFormatContext, AVFormatContextDeleter>(
get_format_context(src, device, option)) {
if (avformat_find_stream_info(ptr.get(), NULL) < 0)
throw std::runtime_error("Failed to find stream information.");
}
AVFormatContextPtr::AVFormatContextPtr(AVFormatContext* p)
: Wrapper<AVFormatContext, AVFormatContextDeleter>(p) {}

////////////////////////////////////////////////////////////////////////////////
// AVPacket
Expand Down Expand Up @@ -151,7 +145,7 @@ void AVCodecContextDeleter::operator()(AVCodecContext* p) {
};

namespace {
AVCodecContext* get_codec_context(
const AVCodec* get_decode_codec(
enum AVCodecID codec_id,
const std::string& decoder_name) {
const AVCodec* pCodec = decoder_name.empty()
Expand All @@ -168,25 +162,29 @@ AVCodecContext* get_codec_context(
}
throw std::runtime_error(ss.str());
}
return pCodec;
}

} // namespace

AVCodecContextPtr get_decode_context(
enum AVCodecID codec_id,
const std::string& decoder_name) {
const AVCodec* pCodec = get_decode_codec(codec_id, decoder_name);

AVCodecContext* pCodecContext = avcodec_alloc_context3(pCodec);
if (!pCodecContext) {
throw std::runtime_error("Failed to allocate CodecContext.");
}
return pCodecContext;
return AVCodecContextPtr(pCodecContext);
}

void init_codec_context(
AVCodecContext* pCodecContext,
AVCodecParameters* pParams,
const std::string& decoder_name,
const std::map<std::string, std::string>& decoder_option) {
const AVCodec* pCodec = decoder_name.empty()
? avcodec_find_decoder(pParams->codec_id)
: avcodec_find_decoder_by_name(decoder_name.c_str());

// No need to check if pCodec is null as it's been already checked in
// get_codec_context
const AVCodec* pCodec = get_decode_codec(pParams->codec_id, decoder_name);

if (avcodec_parameters_to_context(pCodecContext, pParams) < 0) {
throw std::runtime_error("Failed to set CodecContext parameter.");
Expand All @@ -206,16 +204,10 @@ void init_codec_context(
pParams->channel_layout =
av_get_default_channel_layout(pCodecContext->channels);
}
} // namespace

AVCodecContextPtr::AVCodecContextPtr(
AVCodecParameters* pParam,
const std::string& decoder_name,
const std::map<std::string, std::string>& decoder_option)
: Wrapper<AVCodecContext, AVCodecContextDeleter>(
get_codec_context(pParam->codec_id, decoder_name)) {
init_codec_context(ptr.get(), pParam, decoder_name, decoder_option);
}
AVCodecContextPtr::AVCodecContextPtr(AVCodecContext* p)
: Wrapper<AVCodecContext, AVCodecContextDeleter>(p) {}

////////////////////////////////////////////////////////////////////////////////
// AVFilterGraph
////////////////////////////////////////////////////////////////////////////////
Expand Down
28 changes: 20 additions & 8 deletions torchaudio/csrc/ffmpeg/ffmpeg.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,12 +64,15 @@ struct AVFormatContextDeleter {

struct AVFormatContextPtr
: public Wrapper<AVFormatContext, AVFormatContextDeleter> {
AVFormatContextPtr(
const std::string& src,
const std::string& device,
const std::map<std::string, std::string>& option);
AVFormatContextPtr(AVFormatContext*);
};

// create format context for reading media
AVFormatContextPtr get_input_format_context(
const std::string& src,
const std::string& device,
const std::map<std::string, std::string>& option);

////////////////////////////////////////////////////////////////////////////////
// AVPacket
////////////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -118,12 +121,21 @@ struct AVCodecContextDeleter {
};
struct AVCodecContextPtr
: public Wrapper<AVCodecContext, AVCodecContextDeleter> {
AVCodecContextPtr(
AVCodecParameters* pParam,
const std::string& decoder,
const std::map<std::string, std::string>& decoder_option);
AVCodecContextPtr(AVCodecContext*);
};

// Allocate codec context from either decoder name or ID
AVCodecContextPtr get_decode_context(
enum AVCodecID codec_id,
const std::string& decoder);

// Initialize codec context with the parameters
void init_codec_context(
AVCodecContext* pCodecContext,
AVCodecParameters* pParams,
const std::string& decoder_name,
const std::map<std::string, std::string>& decoder_option);

////////////////////////////////////////////////////////////////////////////////
// AVFilterGraph
////////////////////////////////////////////////////////////////////////////////
Expand Down
5 changes: 4 additions & 1 deletion torchaudio/csrc/ffmpeg/streamer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,10 @@ Streamer::Streamer(
const std::string& src,
const std::string& device,
const std::map<std::string, std::string>& option)
: pFormatContext(src, device, option) {
: pFormatContext(get_input_format_context(src, device, option)) {
if (avformat_find_stream_info(pFormatContext, nullptr) < 0)
throw std::runtime_error("Failed to find stream information.");

processors =
std::vector<std::unique_ptr<StreamProcessor>>(pFormatContext->nb_streams);
for (int i = 0; i < pFormatContext->nb_streams; ++i) {
Expand Down

0 comments on commit 899e679

Please sign in to comment.