Страницы

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

понедельник, 6 января 2020 г.

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

#cpp #ffmpeg


Есть строка с SDP информацией, содержащей всю нужную информацию по кодекам. Не хочется
создавать для нее файл, передавать его в avformat_open_input, а затем удалять и так
каждый раз.  А надо бы разбирать sdp-строку и настраивать тип входящего кодека и проч.
без создания файла.
Я не нашел функционала ffmpeg, который бы со строки инитил бы кодеки. Может, кто-то
знает его?
Или придется писать свой парсер и вручную настраивать кодеки?
    


Ответы

Ответ 1



Смотря что понимать под нужным функционалом. Ты можешь созать свой 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.

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

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