Initial import from SVN
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
#include <cassert>
|
||||
#include <stdexcept>
|
||||
#include <iostream>
|
||||
|
||||
#include "Codec.hpp"
|
||||
|
||||
Codec::Codec(enum CodecID codec, Type type )
|
||||
: _codec(nullptr)
|
||||
{
|
||||
if (type == Encoder)
|
||||
_codec = avcodec_find_encoder(codec);
|
||||
else if (type == Decoder)
|
||||
_codec = avcodec_find_decoder(codec);
|
||||
|
||||
if (_codec == nullptr) {
|
||||
std::cerr << "Codec constructor failed! codec = " << codec << ", type = " << type << std::endl;
|
||||
throw std::runtime_error("can't find codec using this id!");
|
||||
}
|
||||
}
|
||||
|
||||
Codec::Codec(const AVCodec* codec)
|
||||
: _codec(codec)
|
||||
{
|
||||
assert(_codec != nullptr);
|
||||
}
|
||||
|
||||
Codec::~Codec()
|
||||
{
|
||||
if (_codec == nullptr) {
|
||||
// TODO release iif ownership has not been taken?
|
||||
// av_codec_close(_codec);
|
||||
}
|
||||
}
|
||||
|
||||
const AVCodec*
|
||||
Codec::get() const
|
||||
{
|
||||
assert(_codec != nullptr);
|
||||
return _codec;
|
||||
}
|
||||
|
||||
Codec::Id
|
||||
Codec::getId() const
|
||||
{
|
||||
assert(_codec != nullptr);
|
||||
return _codec->id;
|
||||
}
|
||||
|
||||
std::string
|
||||
Codec::getName() const
|
||||
{
|
||||
assert(_codec != nullptr);
|
||||
return _codec->name;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
#ifndef CODEC_HPP__
|
||||
#define CODEC_HPP__
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <boost/utility.hpp>
|
||||
|
||||
#include "Common.hpp"
|
||||
|
||||
class Codec : boost::noncopyable
|
||||
{
|
||||
friend class CodecContext;
|
||||
friend class FormatContext;
|
||||
friend class OutputFormatContext;
|
||||
|
||||
public:
|
||||
|
||||
typedef enum CodecID Id;
|
||||
enum Type {
|
||||
Encoder,
|
||||
Decoder,
|
||||
};
|
||||
|
||||
Codec(Id codecId, Type type);
|
||||
Codec(const AVCodec* codec); // Attach existing codec
|
||||
~Codec();
|
||||
|
||||
Id getId() const;
|
||||
std::string getName() const;
|
||||
|
||||
private:
|
||||
|
||||
const AVCodec* get() const;
|
||||
const AVCodec* _codec;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,35 @@
|
||||
#include <stdexcept>
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <boost/array.hpp>
|
||||
|
||||
#include "CodecContext.hpp"
|
||||
|
||||
namespace Av
|
||||
{
|
||||
|
||||
CodecContext::CodecContext(AVCodecContext* CodecContext)
|
||||
: _codecContext(CodecContext)
|
||||
{
|
||||
assert(_codecContext != nullptr);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CodecContext::dumpInfo(std::ostream& ost) const
|
||||
{
|
||||
ost << "BitRate = " << getBitRate() << ", SampleFormat = " << getSampleFormat() << ", SampleRate = " << getSampleRate() << ", ChannelLayout = " << getChannelLayout() << ", NbChannels = " << getNbChannels() << ", Timebase = " << getTimeBase().num << "/" << getTimeBase().den;
|
||||
}
|
||||
|
||||
|
||||
std::string
|
||||
CodecContext::getCodecDesc(void) const
|
||||
{
|
||||
std::vector<char> buf(256, 0);
|
||||
avcodec_string(&buf[0], buf.size(), _codecContext, 0);
|
||||
|
||||
return std::string(buf.begin(), buf.end());
|
||||
}
|
||||
|
||||
} // namespace Av
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
#ifndef CODEC_CONTEXT_HPP
|
||||
#define CODEC_CONTEXT_HPP
|
||||
|
||||
#include <boost/utility.hpp>
|
||||
#include <iostream>
|
||||
|
||||
#include "Codec.hpp"
|
||||
|
||||
namespace Av
|
||||
{
|
||||
|
||||
class CodecContext
|
||||
{
|
||||
public:
|
||||
|
||||
CodecContext(AVCodecContext* CodecContext); // Attach existing codec context (no free will be done)
|
||||
|
||||
// Codec getCodec();
|
||||
|
||||
enum AVMediaType getType(void) const { return _codecContext->codec_type; }
|
||||
Codec::Id getCodecId(void) const { return _codecContext->codec_id; }
|
||||
|
||||
std::string getCodecDesc(void) const;
|
||||
|
||||
// Accessors
|
||||
std::size_t getBitRate() const {return _codecContext->bit_rate;}
|
||||
AVSampleFormat getSampleFormat() const {return _codecContext->sample_fmt;}
|
||||
std::size_t getSampleRate() const {return _codecContext->sample_rate;}
|
||||
std::uint64_t getChannelLayout() const {return _codecContext->channel_layout;}
|
||||
std::size_t getNbChannels() const {return _codecContext->channels; }
|
||||
AVRational getTimeBase() const {return _codecContext->time_base; }
|
||||
|
||||
void dumpInfo(std::ostream& ost) const;
|
||||
|
||||
private:
|
||||
AVCodecContext* native() { return _codecContext; }
|
||||
|
||||
AVCodecContext* _codecContext;
|
||||
};
|
||||
|
||||
} // namespace Av
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
#include "Common.hpp"
|
||||
|
||||
#include <boost/array.hpp>
|
||||
|
||||
std::string
|
||||
AvError::to_str(void) const
|
||||
{
|
||||
boost::array<char, 128> buf = {0};
|
||||
if (av_strerror(_errnum, buf.data(), buf.size()) == 0)
|
||||
return std::string(&buf[0]);
|
||||
else
|
||||
return "Unknown error";
|
||||
|
||||
}
|
||||
|
||||
|
||||
std::ostream& operator<<(std::ostream& ost, const AvError& err)
|
||||
{
|
||||
ost << err.to_str();
|
||||
return ost;
|
||||
}
|
||||
|
||||
void AvInit()
|
||||
{
|
||||
/* register all the codecs */
|
||||
avcodec_register_all();
|
||||
av_register_all();
|
||||
std::cout << "AVCDOEC VERSION = " << avcodec_version() << std::endl;
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
#ifndef TRANSCODE_COMMON_HPP__
|
||||
#define TRANSCODE_COMMON_HPP__
|
||||
|
||||
// Hack to properly iinclude libavcodec/avcodec.h...
|
||||
//
|
||||
#define __STDC_CONSTANT_MACROS
|
||||
#ifdef _STDINT_H
|
||||
#undef _STDINT_H
|
||||
#endif
|
||||
# include <stdint.h>
|
||||
extern "C" {
|
||||
#include <libavcodec/avcodec.h>
|
||||
#include <libavformat/avformat.h>
|
||||
#include <libavutil/channel_layout.h>
|
||||
#include <libavutil/mathematics.h>
|
||||
}
|
||||
|
||||
#include <string>
|
||||
|
||||
|
||||
void AvInit();
|
||||
|
||||
class AvError
|
||||
{
|
||||
public:
|
||||
AvError() : _errnum(0) {}
|
||||
AvError(int ernum) : _errnum(ernum) {}
|
||||
|
||||
void operator=(int errnum) { _errnum = errnum; }
|
||||
|
||||
operator bool() { return _errnum < 0; }
|
||||
|
||||
std::string to_str() const;
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& ost, const AvError&);
|
||||
|
||||
bool eof() { return _errnum == AVERROR_EOF; } // TODO
|
||||
|
||||
private:
|
||||
int _errnum;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,31 @@
|
||||
#include "Dictionary.hpp"
|
||||
|
||||
|
||||
namespace Av
|
||||
{
|
||||
|
||||
Dictionary::Dictionary(AVDictionary* dictionary)
|
||||
: _dictionary(dictionary)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
Dictionary::get(std::map<std::string, std::string>& entries)
|
||||
{
|
||||
AVDictionaryEntry *tag = NULL;
|
||||
while ((tag = av_dict_get(_dictionary, "", tag, AV_DICT_IGNORE_SUFFIX))) {
|
||||
entries.insert( std::make_pair(tag->key, tag->value));
|
||||
}
|
||||
}
|
||||
|
||||
std::string
|
||||
Dictionary::get(std::string key)
|
||||
{
|
||||
AVDictionaryEntry *tag = NULL;
|
||||
tag = av_dict_get(_dictionary, key.c_str(), tag, 0);
|
||||
|
||||
return tag != NULL ? std::string(tag->value) : std::string();
|
||||
}
|
||||
|
||||
} // namespace Av
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
#ifndef AV_DICTIONARY_HPP
|
||||
#define AV_DICTIONARY_HPP
|
||||
|
||||
#include <map>
|
||||
#include "Common.hpp"
|
||||
|
||||
namespace Av
|
||||
{
|
||||
|
||||
class Dictionary
|
||||
{
|
||||
public:
|
||||
Dictionary(AVDictionary* dictionary);
|
||||
|
||||
// Get all
|
||||
void get(std::map<std::string, std::string>& entries);
|
||||
|
||||
// get a single entry
|
||||
std::string get(std::string key);
|
||||
|
||||
private:
|
||||
AVDictionary* _dictionary;
|
||||
};
|
||||
|
||||
} // namespace Av
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
|
||||
#include "FormatContext.hpp"
|
||||
|
||||
namespace Av
|
||||
{
|
||||
|
||||
FormatContext::FormatContext()
|
||||
: _context(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
FormatContext::~FormatContext()
|
||||
{
|
||||
}
|
||||
|
||||
} // namespace Av
|
||||
@@ -0,0 +1,33 @@
|
||||
#ifndef FORMAT_CONTEXT_HPP
|
||||
#define FORMAT_CONTEXT_HPP
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#include "Common.hpp"
|
||||
|
||||
namespace Av
|
||||
{
|
||||
|
||||
class FormatContext
|
||||
{
|
||||
public:
|
||||
FormatContext();
|
||||
~FormatContext();
|
||||
|
||||
|
||||
protected:
|
||||
void native(AVFormatContext* c) { _context = c;}
|
||||
AVFormatContext* native() { return _context; }
|
||||
const AVFormatContext* native() const { return _context; }
|
||||
|
||||
private:
|
||||
|
||||
AVFormatContext* _context;
|
||||
|
||||
|
||||
};
|
||||
|
||||
} // namespace Av
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
#include <stdexcept>
|
||||
#include <iostream>
|
||||
|
||||
#include "InputFormatContext.hpp"
|
||||
|
||||
namespace Av
|
||||
{
|
||||
|
||||
InputFormatContext::InputFormatContext(const boost::filesystem::path& p)
|
||||
: _path(p)
|
||||
{
|
||||
std::cout << "Opening '" << p.string().c_str() << "'" << std::endl;
|
||||
|
||||
AVFormatContext* context = nullptr;
|
||||
|
||||
// The last three parameters specify the file format, buffer size and
|
||||
// format parameters. By simply specifying NULL or 0 we ask libavformat
|
||||
// to auto-detect the format and use a default buffer size.
|
||||
AvError error = avformat_open_input(&context, p.string().c_str(), nullptr, nullptr);
|
||||
if (error)
|
||||
{
|
||||
std::cerr << "Cannot open '" << p.string() << "', avformat_open_input returned " << error << std::endl;
|
||||
throw std::runtime_error("avformat_open_input failed: " + error.to_str());
|
||||
}
|
||||
|
||||
native(context);
|
||||
|
||||
}
|
||||
|
||||
InputFormatContext::~InputFormatContext()
|
||||
{
|
||||
AVFormatContext* context = native();
|
||||
avformat_close_input(&context);
|
||||
}
|
||||
|
||||
std::vector<Stream>
|
||||
InputFormatContext::getStreams(void)
|
||||
{
|
||||
std::vector<Stream> res;
|
||||
|
||||
for (std::size_t i = 0; i < native()->nb_streams; ++i) {
|
||||
res.push_back( Stream(native()->streams[i]));
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
InputFormatContext::getBestStreamIdx(AVMediaType type, Stream::Idx& index)
|
||||
{
|
||||
int res = av_find_best_stream(native(),
|
||||
type,
|
||||
-1, // Auto
|
||||
-1, // Auto
|
||||
NULL,
|
||||
0
|
||||
);
|
||||
|
||||
AvError error(res);
|
||||
if (error) {
|
||||
std::cerr << "Cannot get best stream for type " << type << ": " << error << std::endl;
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
index = res;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
InputFormatContext::findStreamInfo(void)
|
||||
{
|
||||
native()->max_analyze_duration = 10 * AV_TIME_BASE; // 10 secs
|
||||
AvError err = avformat_find_stream_info(native(), NULL);
|
||||
if (err) {
|
||||
std::cerr << "Couldn't find stream information: " << err << std::endl;
|
||||
throw std::runtime_error("av_find_stream_info failed!");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::size_t
|
||||
InputFormatContext::getDurationSecs() const
|
||||
{
|
||||
if (native()->duration != AV_NOPTS_VALUE )
|
||||
return native()->duration / AV_TIME_BASE;
|
||||
else
|
||||
return 0; // TODO, do something better?
|
||||
}
|
||||
|
||||
Dictionary
|
||||
InputFormatContext::getMetadata(void)
|
||||
{
|
||||
return Dictionary(native()->metadata);
|
||||
|
||||
}
|
||||
|
||||
} //namespace Av
|
||||
@@ -0,0 +1,43 @@
|
||||
#ifndef INPUT_FORMAT_CONTEXT_HPP
|
||||
#define INPUT_FORMAT_CONTEXT_HPP
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#include "FormatContext.hpp"
|
||||
#include "Stream.hpp"
|
||||
#include "Dictionary.hpp"
|
||||
|
||||
namespace Av
|
||||
{
|
||||
|
||||
class InputFormatContext : public FormatContext
|
||||
{
|
||||
public:
|
||||
|
||||
InputFormatContext(const boost::filesystem::path& p);
|
||||
~InputFormatContext();
|
||||
|
||||
|
||||
Dictionary getMetadata(void); // metadata access
|
||||
|
||||
// Scan file
|
||||
void findStreamInfo();
|
||||
|
||||
std::vector<Stream> getStreams(void);
|
||||
|
||||
bool getBestStreamIdx(enum AVMediaType type, Stream::Idx& idx);
|
||||
|
||||
std::size_t getDurationSecs() const;
|
||||
|
||||
private:
|
||||
boost::filesystem::path _path;
|
||||
|
||||
|
||||
};
|
||||
|
||||
} // namespace av
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
#include <cassert>
|
||||
#include "Stream.hpp"
|
||||
|
||||
namespace Av
|
||||
{
|
||||
|
||||
Stream::Stream(AVStream* stream)
|
||||
: _stream(stream)
|
||||
{
|
||||
assert(_stream != nullptr);
|
||||
assert(_stream->codec != nullptr);
|
||||
}
|
||||
|
||||
CodecContext
|
||||
Stream::getCodecContext()
|
||||
{
|
||||
return _stream->codec;
|
||||
}
|
||||
|
||||
Dictionary
|
||||
Stream::getMetadata(void)
|
||||
{
|
||||
return Dictionary(_stream->metadata);
|
||||
}
|
||||
|
||||
} // namespace Av
|
||||
@@ -0,0 +1,35 @@
|
||||
#ifndef STREAM_HPP__
|
||||
#define STREAM_HPP__
|
||||
|
||||
#include "Common.hpp"
|
||||
|
||||
#include "CodecContext.hpp"
|
||||
#include "Dictionary.hpp"
|
||||
|
||||
namespace Av
|
||||
{
|
||||
|
||||
class Stream
|
||||
{
|
||||
friend class InputFormatContext;
|
||||
|
||||
public:
|
||||
// Attach existing stream
|
||||
Stream(AVStream* stream);
|
||||
|
||||
typedef size_t Idx;
|
||||
|
||||
// Idx getIdx() const { return _stream->index; }
|
||||
|
||||
Dictionary getMetadata(void);
|
||||
CodecContext getCodecContext(void);
|
||||
|
||||
private:
|
||||
|
||||
AVStream* _stream;
|
||||
};
|
||||
|
||||
} // namespace Av
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user