Skip to content

Commit

Permalink
Basic ChannelLayout wrapper
Browse files Browse the repository at this point in the history
  • Loading branch information
h4tr3d committed Feb 25, 2023
1 parent 97851eb commit decba93
Show file tree
Hide file tree
Showing 2 changed files with 310 additions and 0 deletions.
201 changes: 201 additions & 0 deletions src/channellayout.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
#include <utility>
#include <cstring>

#include "channellayout.h"

namespace av {

static constexpr size_t BufferSize = 128;


std::string channel_name(AVChannel channel)
{
char buf[BufferSize]{};
av_channel_name(buf, sizeof(buf), channel);
return buf;
}

std::string channel_description(AVChannel channel)
{
char buf[BufferSize]{};
av_channel_description(buf, sizeof(buf), channel);
return buf;
}

AVChannel channel_from_string(const std::string &name)
{
return channel_from_string(name.c_str());
}

AVChannel channel_from_string(const char *name)
{
return av_channel_from_string(name);
}


ChannelLayoutView::ChannelLayoutView() noexcept
{
}

ChannelLayoutView::ChannelLayoutView(const AVChannelLayout &layout) noexcept
: m_layout(layout)
{
}

void ChannelLayoutView::dumpLayouts()
{
//std::string;
iterate([] (const ChannelLayoutView &ch) {
char buf[BufferSize]{};
av_channel_layout_describe(ch.raw(), buf, sizeof(buf));
std::string channels;
for (int i = 0; i < 63; i++) {
auto idx = ch.index(AVChannel(i));
if (idx >= 0) {
if (idx)
channels.push_back('+');
channels.append(channel_name(AVChannel(i)));
}
}
return false; // is not done
});
}

AVChannelLayout *ChannelLayoutView::raw()
{
return &m_layout;
}

const AVChannelLayout *ChannelLayoutView::raw() const
{
return &m_layout;
}

int ChannelLayoutView::channels() const noexcept
{
return m_layout.nb_channels;
}

uint64_t ChannelLayoutView::layout() const noexcept
{
return m_layout.order == AV_CHANNEL_ORDER_NATIVE ? m_layout.u.mask : 0;
}

uint64_t ChannelLayoutView::subset(uint64_t mask) const noexcept
{
return av_channel_layout_subset(&m_layout, mask);
}

bool ChannelLayoutView::isValid() const noexcept
{
return av_channel_layout_check(&m_layout);
}

std::string ChannelLayoutView::describe() const
{
char buf[BufferSize]{};
av_channel_layout_describe(&m_layout, buf, sizeof(buf));
return buf;
}

void ChannelLayoutView::describe(std::string &desc) const
{
// TBD
if (desc.capacity()) {
if (!desc.size())
desc.resize(desc.capacity());
av_channel_layout_describe(&m_layout, desc.data(), desc.size());
desc.resize(std::strlen(desc.data())); // hack?
} else {
desc = describe();
}
}

int ChannelLayoutView::index(AVChannel channel) const
{
return av_channel_layout_index_from_channel(&m_layout, channel);
}

int ChannelLayoutView::index(const char *name) const
{
return av_channel_layout_index_from_string(&m_layout, name);
}

AVChannel ChannelLayoutView::channel(unsigned int index) const
{
return av_channel_layout_channel_from_index(&m_layout, index);
}

AVChannel ChannelLayoutView::channel(const char *name) const
{
return av_channel_layout_channel_from_string(&m_layout, name);
}

bool ChannelLayoutView::operator==(const ChannelLayoutView &other) const noexcept
{
return av_channel_layout_compare(&m_layout, &other.m_layout) == 0;
}


ChannelLayout::ChannelLayout(const ChannelLayout &other)
: ChannelLayout()
{
// TODO: error checking
av_channel_layout_copy(&m_layout, &other.m_layout);
}

ChannelLayout &ChannelLayout::operator=(const ChannelLayout &other)
{
ChannelLayout(other).swap(*this);
return *this;
}

ChannelLayout::ChannelLayout(ChannelLayout &&other)
: ChannelLayout()
{
m_layout = std::move(other.m_layout);
memset(&other.m_layout, 0, sizeof(other.m_layout)); // avoid double memory clean up
}

ChannelLayout &ChannelLayout::operator=(ChannelLayout&& other)
{
ChannelLayout(std::move(other)).swap(*this);
return *this;
}

ChannelLayout::~ChannelLayout()
{
av_channel_layout_uninit(&m_layout);
}

ChannelLayout::ChannelLayout(std::bitset<64> mask)
{
// TODO: error checking
av_channel_layout_from_mask(&m_layout, mask.to_ullong());
}

ChannelLayout::ChannelLayout(const char *str)
{
// TODO: error checking
av_channel_layout_from_string(&m_layout, str);
}

ChannelLayout::ChannelLayout(int channels)
{
// TODO: error checking
av_channel_layout_default(&m_layout, channels);
}

void ChannelLayout::release()
{
memset(&m_layout, 0, sizeof(m_layout));
}

void ChannelLayout::swap(ChannelLayout &other)
{
//std::swap(*raw(), *other.raw());
std::swap(m_layout, other.m_layout);
}


} // namespace av
109 changes: 109 additions & 0 deletions src/channellayout.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
#pragma once

#include <string>
#include <string_view>
#include <bitset>

extern "C" {
#include <libavutil/channel_layout.h>
}

namespace av {

std::string channel_name(AVChannel channel);
std::string channel_description(AVChannel channel);
AVChannel channel_from_string(const std::string &name);
AVChannel channel_from_string(const char *name);

class ChannelLayoutView
{
public:
ChannelLayoutView() noexcept;
// implicit by design
ChannelLayoutView(const AVChannelLayout &layout) noexcept;

// ???
//+ const AVChannelLayout *av_channel_layout_standard(void **opaque);
template<typename Callable>
static void iterate(Callable callable) {
void *iter = nullptr;
const AVChannelLayout *playout;
while ((playout = av_channel_layout_standard(&iter))) {
if (callable(ChannelLayoutView(*playout)))
break;
}
}

static void dumpLayouts();

//+ int av_channel_layout_describe(const AVChannelLayout *channel_layout, char *buf, size_t buf_size);
//+ int av_channel_layout_index_from_channel(const AVChannelLayout *channel_layout, enum AVChannel channel);
//+ int av_channel_layout_index_from_string(const AVChannelLayout *channel_layout, const char *name);
//+ enum AVChannel av_channel_layout_channel_from_index(const AVChannelLayout *channel_layout, unsigned int idx);
//+ enum AVChannel av_channel_layout_channel_from_string(const AVChannelLayout *channel_layout, const char *name);
//+ uint64_t av_channel_layout_subset(const AVChannelLayout *channel_layout, uint64_t mask);
//+ int av_channel_layout_check(const AVChannelLayout *channel_layout);
//+ int av_channel_layout_compare(const AVChannelLayout *chl, const AVChannelLayout *chl1);

AVChannelLayout *raw();
const AVChannelLayout *raw() const;

int channels() const noexcept;
uint64_t layout() const noexcept;
uint64_t subset(uint64_t mask) const noexcept;
bool isValid() const noexcept;
std::string describe() const;
void describe(std::string &desc) const;

int index(AVChannel channel) const;
int index(const char *name) const;

AVChannel channel(unsigned int index) const;
AVChannel channel(const char *name) const;

bool operator==(const ChannelLayoutView &other) const noexcept;

protected:
AVChannelLayout m_layout{};
};



class ChannelLayout : public ChannelLayoutView
{
public:
ChannelLayout() = default;

using ChannelLayoutView::ChannelLayoutView;

ChannelLayout(const ChannelLayout& other);
ChannelLayout& operator=(const ChannelLayout& other);

ChannelLayout(ChannelLayout&& other);
ChannelLayout& operator=(ChannelLayout&& other);

~ChannelLayout();

//+ void av_channel_layout_uninit(AVChannelLayout *channel_layout);
//
//+ int av_channel_layout_from_mask(AVChannelLayout *channel_layout, uint64_t mask);
//+ int av_channel_layout_from_string(AVChannelLayout *channel_layout, const char *str);
//+ void av_channel_layout_default(AVChannelLayout *ch_layout, int nb_channels);
//+ int av_channel_layout_copy(AVChannelLayout *dst, const AVChannelLayout *src);

//explicit ChannelLayout(uint64_t mask);
explicit ChannelLayout(std::bitset<64> mask);
explicit ChannelLayout(const char *str);
explicit ChannelLayout(int channels);

// Stop control AVChannelLayout
void release();

private:
void swap(ChannelLayout &other);

};


} // namespace av

0 comments on commit decba93

Please sign in to comment.