Есть строка с SDP информацией, содержащей всю нужную информацию по кодекам. Не хочется создавать для нее файл, передавать его в avformat_open_input, а затем удалять и так каждый раз. А надо бы разбирать sdp-строку и настраивать тип входящего кодека и проч. без создания файла. Я не нашел функционала ffmpeg, который бы со строки инитил бы кодеки. Может, кто-то знает его? Или придется писать свой парсер и вручную настраивать кодеки?
Ответ
Смотря что понимать под нужным функционалом. Ты можешь созать свой AVIO контекст, а он, в качестве источника данных, может хоть базу данных, хоть общую память, хоть просто кусок памяти использовать.
Курить:
avio_alloc_context()
AVFormatContext::pb
avformat_open_input()
Т.е. алгоритм ваших действий будет примерно такой:
Аллоцировать AVFormatContext (avformat_alloc_context())
Аллоцировать AVIOContext с нужными функциями, и структурой контекста
Присвоить AVFormatContext::pb значение вашего контекста IO
Вызвать avformat_open_input() где первым параметром передать указатель на ваш, уже аллоцированный, контекст формата - он любезно им воспользуется.
При вызове вашей процедуры чтения вполне возможно, что запросится только часть данных, поэтому нужно где-то хранить позицию чтения (opaque вам в помощь) и контроллировать границу данных (когда у вас осталось, допустим, 2 байта, а запросили буфер 1024 - записать только 2 и вернуть реальное число записанный байт, т.е. снова - 2).
А вот и рабочий, компилируемый (GCC 4.9, FFmpeg 2.8.6) пример:
#include
extern "C" {
#include
using namespace std;
static const char* SDP_DATA = R"(
v=0
o=- 1376063087593 1 IN IP4 127.0.0.1
s=-
t=0 0
m=audio 50008 RTP/AVP 0
c=IN IP4 192.168.2.196
a=rtcp:50009 IN IP4 192.168.2.196
a=rtpmap:0 PCMU/8000
a=sendrecv
m=video 50010 RTP/AVP 120
c=IN IP4 192.168.2.196
a=rtcp:50011 IN IP4 192.168.2.196
a=rtpmap:120 VP8/90000
a=sendrecv
a=rtcp-fb:* nack
a=rtcp-fb:* ccm fir
)";
struct SdpOpaque
{
using Vector = std::vector
int sdp_read(void *opaque, uint8_t *buf, int size) noexcept
{
assert(opaque);
assert(buf);
auto octx = static_cast
if (octx->pos == octx->data.end()) {
return 0;
}
auto dist = static_cast
std::copy(octx->pos, octx->pos + count, buf);
octx->pos += count;
return count;
}
int sdp_open(AVFormatContext **pctx, const char *data, AVDictionary **options) noexcept
{
assert(pctx);
*pctx = avformat_alloc_context();
assert(*pctx);
const size_t avioBufferSize = 4096;
auto avioBuffer = static_cast
opaque->data = SdpOpaque::Vector(data, data + strlen(data));
opaque->pos = opaque->data.begin();
auto pbctx = avio_alloc_context(avioBuffer, avioBufferSize, 0, opaque, sdp_read, nullptr, nullptr);
assert(pbctx);
(*pctx)->pb = pbctx;
auto infmt = av_find_input_format("sdp");
return avformat_open_input(pctx, "memory.sdp", infmt, options);
}
void sdp_close(AVFormatContext **fctx) noexcept
{
assert(fctx);
auto ctx = *fctx;
// Opaque can be non-POD type, free it before and assign to null
auto opaque = static_cast
avio_close(ctx->pb);
avformat_close_input(fctx);
}
int main()
{
av_register_all();
avformat_network_init();
AVFormatContext *sdpctx = nullptr;
sdp_open(&sdpctx, SDP_DATA, nullptr);
av_dump_format(sdpctx, 0, "memory.sdp", 0);
// Copy settings to target context from SDP context:
/*
for (size_t i = 0; i < sdpctx->nb_streams; ++i) {
AVStream *st = avformat_new_stream(otherctx, nullptr);
st->id = i;
avcodec_copy_context(st->codec, sdpctx->streams[i]->codec);
st->time_base = sdpctx->streams[i]->time_base;
}
*/
sdp_close(&sdpctx);
return 0;
}
После запуска выводит:
Input #0, sdp, from 'memory.sdp':
Metadata:
title : -
Duration: N/A, bitrate: N/A
Stream #0:0: Audio: pcm_mulaw, 8000 Hz, 1 channels, 64 kb/s
Stream #0:1: Video: vp8, none, 90k tbn
Собственно, что и описано в SDP.
Комментариев нет:
Отправить комментарий