Страницы

Поиск по вопросам

четверг, 14 февраля 2019 г.

аналог avformat_open_input со строкой вместо файла

Есть строка с 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 #include #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; Vector data; Vector::iterator pos; };
int sdp_read(void *opaque, uint8_t *buf, int size) noexcept { assert(opaque); assert(buf); auto octx = static_cast(opaque);
if (octx->pos == octx->data.end()) { return 0; }
auto dist = static_cast(std::distance(octx->pos, octx->data.end())); auto count = std::min(size, dist);
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(av_malloc(avioBufferSize)); auto opaque = new SdpOpaque();
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(ctx->pb->opaque); delete opaque; ctx->pb->opaque = nullptr;
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.

Комментариев нет:

Отправить комментарий