diff --git a/ffmpeg-plugin/6.1/0001-mcm-add-in-out-dev-support.patch b/ffmpeg-plugin/6.1/0001-mcm-add-in-out-dev-support.patch index 59094a9f..8da11dc1 100644 --- a/ffmpeg-plugin/6.1/0001-mcm-add-in-out-dev-support.patch +++ b/ffmpeg-plugin/6.1/0001-mcm-add-in-out-dev-support.patch @@ -1,19 +1,19 @@ -From 07fac1a4532e1d10660e8e138360b0e3673aac9e Mon Sep 17 00:00:00 2001 -From: Ilichev, Konstantin -Date: Tu, 14 May 2024 05:48:00 +0100 -Subject: [PATCH 1] Enable FFmpeg support in MCM +From fbb0700ea7bd9b055ae9e43746a7751be88a8955 Mon Sep 17 00:00:00 2001 +From: Konstantin Ilichev +Date: Wed, 21 Aug 2024 14:55:08 +0000 +Subject: [PATCH] Enable FFmpeg support in MCM --- - configure | 6 ++++++ - libavdevice/Makefile | 2 ++ - libavdevice/alldevices.c | 2 ++ - 3 files changed, 10 insertions(+) + configure | 9 +++++++++ + libavdevice/Makefile | 5 +++++ + libavdevice/alldevices.c | 5 +++++ + 3 files changed, 19 insertions(+) diff --git a/configure b/configure -index 96b181fd21..e5320f8751 100755 +index 5af693c954..60caa4ebdf 100755 --- a/configure +++ b/configure -@@ -292,6 +292,7 @@ External library support: +@@ -285,6 +285,7 @@ External library support: --enable-libvo-amrwbenc enable AMR-WB encoding via libvo-amrwbenc [no] --enable-libvorbis enable Vorbis en/decoding via libvorbis, native implementation exists [no] @@ -21,7 +21,7 @@ index 96b181fd21..e5320f8751 100755 --enable-libvpx enable VP8 and VP9 de/encoding via libvpx [no] --enable-libwebp enable WebP encoding via libwebp [no] --enable-libx264 enable H.264 encoding via x264 [no] -@@ -1904,6 +1905,7 @@ EXTERNAL_LIBRARY_LIST=" +@@ -1841,6 +1842,7 @@ EXTERNAL_LIBRARY_LIST=" jni ladspa lcms2 @@ -29,16 +29,19 @@ index 96b181fd21..e5320f8751 100755 libaom libaribcaption libass -@@ -3689,6 +3691,8 @@ xwma_demuxer_select="riffdec" +@@ -3567,6 +3569,11 @@ xwma_demuxer_select="riffdec" android_camera_indev_deps="android camera2ndk mediandk pthreads" alsa_indev_deps="alsa" alsa_outdev_deps="alsa" +mcm_indev_deps="libmcm_dp" +mcm_outdev_deps="libmcm_dp" ++mcm_audio_indev_deps="libmcm_dp" ++mcm_audio_outdev_deps="libmcm_dp" ++mcm_audio_pcm16_outdev_deps="libmcm_dp" avfoundation_indev_deps="avfoundation corevideo coremedia pthreads" avfoundation_indev_suggest="coregraphics applicationservices" avfoundation_indev_extralibs="-framework Foundation" -@@ -6867,6 +6871,8 @@ enabled libaribb24 && { check_pkg_config libaribb24 "aribb24 > 1.0.3" "ar +@@ -6692,6 +6699,8 @@ enabled libaribb24 && { check_pkg_config libaribb24 "aribb24 > 1.0.3" "ar enabled libaribcaption && require_pkg_config libaribcaption "libaribcaption >= 1.1.1" "aribcaption/aribcaption.h" aribcc_context_alloc enabled lv2 && require_pkg_config lv2 lilv-0 "lilv/lilv.h" lilv_world_new enabled libiec61883 && require libiec61883 libiec61883/iec61883.h iec61883_cmp_connect -lraw1394 -lavc1394 -lrom1394 -liec61883 @@ -48,30 +51,37 @@ index 96b181fd21..e5320f8751 100755 enabled libbluray && require_pkg_config libbluray libbluray libbluray/bluray.h bd_open enabled libbs2b && require_pkg_config libbs2b libbs2b bs2b.h bs2b_open diff --git a/libavdevice/Makefile b/libavdevice/Makefile -index c30449201d..f6a44520ca 100644 +index c30449201d..62bda757c3 100644 --- a/libavdevice/Makefile +++ b/libavdevice/Makefile -@@ -20,6 +20,8 @@ OBJS-$(CONFIG_AUDIOTOOLBOX_OUTDEV) += audiotoolbox.o +@@ -20,6 +20,11 @@ OBJS-$(CONFIG_AUDIOTOOLBOX_OUTDEV) += audiotoolbox.o OBJS-$(CONFIG_AVFOUNDATION_INDEV) += avfoundation.o OBJS-$(CONFIG_BKTR_INDEV) += bktr.o OBJS-$(CONFIG_CACA_OUTDEV) += caca.o -+OBJS-$(CONFIG_MCM_INDEV) += mcm_rx.o -+OBJS-$(CONFIG_MCM_OUTDEV) += mcm_tx.o ++OBJS-$(CONFIG_MCM_INDEV) += mcm_video_rx.o mcm_common.o ++OBJS-$(CONFIG_MCM_OUTDEV) += mcm_video_tx.o mcm_common.o ++OBJS-$(CONFIG_MCM_AUDIO_INDEV) += mcm_audio_rx.o mcm_common.o ++OBJS-$(CONFIG_MCM_AUDIO_OUTDEV) += mcm_audio_tx.o mcm_common.o ++OBJS-$(CONFIG_MCM_AUDIO_PCM16_OUTDEV) += mcm_audio_tx.o mcm_common.o OBJS-$(CONFIG_DECKLINK_OUTDEV) += decklink_enc.o decklink_enc_c.o decklink_common.o OBJS-$(CONFIG_DECKLINK_INDEV) += decklink_dec.o decklink_dec_c.o decklink_common.o OBJS-$(CONFIG_DSHOW_INDEV) += dshow_crossbar.o dshow.o dshow_enummediatypes.o \ diff --git a/libavdevice/alldevices.c b/libavdevice/alldevices.c -index 8a90fcb5d7..4dd6194b02 100644 +index 8a90fcb5d7..fe0eabdd67 100644 --- a/libavdevice/alldevices.c +++ b/libavdevice/alldevices.c -@@ -25,6 +25,8 @@ +@@ -25,6 +25,11 @@ /* devices */ extern const AVInputFormat ff_alsa_demuxer; extern const FFOutputFormat ff_alsa_muxer; +extern const AVInputFormat ff_mcm_demuxer; +extern const FFOutputFormat ff_mcm_muxer; ++extern const AVInputFormat ff_mcm_audio_demuxer; ++extern const FFOutputFormat ff_mcm_audio_muxer; ++extern const FFOutputFormat ff_mcm_audio_pcm16_muxer; extern const AVInputFormat ff_android_camera_demuxer; extern const FFOutputFormat ff_audiotoolbox_muxer; extern const AVInputFormat ff_avfoundation_demuxer; -- +2.34.1 diff --git a/ffmpeg-plugin/README.md b/ffmpeg-plugin/README.md index 9d7e5c63..79f66705 100644 --- a/ffmpeg-plugin/README.md +++ b/ffmpeg-plugin/README.md @@ -26,12 +26,32 @@ Install dependencies and build MCM as described in the top level README.md, para ./build-ffmpeg.sh ``` -## Arguments -TBD +## MCM connection configuration + +The next arguments are supported to configure a connection to MCM + +| Argument | Type | Description | Default | +| --------------- | :-----: | -------------------------------------------------------- | :--------------: | +| `ip_addr` | String | Remote IP address | `"192.168.96.1"` | +| `port` | String | Remote port (Sender), or Local port (Receiver) | `"9001"` | +| `protocol_type` | String | MCM Protocol type (`"auto"`, `"memif"`, etc.) | `"auto"` | +| `payload_type` | String | ST2110 payload type (`"st20"`, `"st22"`, `"st30"`, etc.) | `"st20"` | +| `socket_name` | String | Memif socket name | - | +| `interface_id` | Integer | Memif interface id | `0` | + +## Video configuration + +The next arguments are supported to configure a video transmission + +| Argument | Type | Description | Default | +| -------------- | :----: | ----------------------------------------------- | :-------------: | +| `video_size` | String | Video frame size (`"640x480"`, `"hd720"`, etc.) | `"1920x1080"` | +| `pixel_format` | String | Video pixel format | `"yuv422p10le"` | +| `frame_rate` | String | Video frame rate (`25`, `50`, `60`, etc.) | `25` | -## Run +## Example – Run video transmission -This test run demonstrates sending a video file from the 1st FFmpeg instance to the 2nd FFmpeg instance via MCM and then stream it to a remote machine via UDP. +This example demonstrates sending a video file from the 1st FFmpeg instance to the 2nd FFmpeg instance via MCM and then stream it to a remote machine via UDP. ### NIC setup @@ -46,8 +66,13 @@ TBD 2. Start FFmpeg to receive frames from MCM and stream to a remote machine via UDP ```bash sudo MCM_MEDIA_PROXY_PORT=8002 ffmpeg -re -f mcm \ - -frame_rate 24 -video_size nhd -pixel_format yuv422p10le -protocol_type auto \ - -payload_type st20 -ip_addr 192.168.96.1 -port 9001 \ + -frame_rate 24 \ + -video_size nhd \ + -pixel_format yuv422p10le \ + -protocol_type auto \ + -payload_type st20 \ + -ip_addr 192.168.96.1 \ + -port 9001 \ -i - -vcodec mpeg4 -f mpegts udp://: ``` @@ -60,8 +85,13 @@ TBD 2. Start FFmpeg to stream a video file to the receiver via MCM ```bash sudo MCM_MEDIA_PROXY_PORT=8001 ffmpeg -i -f mcm \ - -frame_rate 24 -video_size nhd -pixel_format yuv422p10le -protocol_type auto \ - -payload_type st20 -ip_addr 192.168.96.2 -port 9001 - + -frame_rate 24 \ + -video_size nhd \ + -pixel_format yuv422p10le \ + -protocol_type auto \ + -payload_type st20 \ + -ip_addr 192.168.96.2 \ + -port 9001 - ``` ### VLC player setup @@ -71,6 +101,104 @@ On the remote machine start the VLC player and open a network stream from the ne udp://@:1234 ``` +## Audio configuration + +The table below shows a proper way to configure the sender and the receiver depending on the audio PCM encoding format + +| Audio encoding | Sender configuration | Receiver configuration | +| --- | --- | --- | +| PCM 24-bit | Output device `mcm_audio` | Input device `mcm_audio` and argument `-pcm_fmt pcm24` +| PCM 16-bit | Output device `mcm_audio_pcm16` | Input device `mcm_audio` and argument `-pcm_fmt pcm16` + +The next arguments are supported to configure an audio transmission + +| Argument | Type | Description | Default | +| ------------- | :-----: | ------------------------------------------------ | :-------: | +| `channels` | Integer | Number of audio channels (`1`, `2`, etc.) | `2` | +| `sample_rate` | Integer | Audio sample rate (`44100`, `48000`, or `96000`) | `48000` | +| `ptime` | String | MTL audio packet time (`"1ms"` or `"125us"`) | `"1ms"` | +| `pcm_fmt` | String | PCM audio format (`"pcm24"` or `"pcm16"`) | `"pcm24"` | + +## Example – Run audio transmission + +This example demonstrates sending an audio file from the 1st FFmpeg instance to the 2nd FFmpeg instance via MCM. + +There are two options of configuration: +* **Option A** for PCM 24-bit encoded audio +* **Option B** for PCM 16-bit encoded audio + +### NIC setup + +TBD + +### Receiver side setup + +1. Start media_proxy + ```bash + sudo media_proxy -d 0000:32:11.1 -i 192.168.96.2 -t 8002 + ``` +2. Start FFmpeg to receive packets from MCM and store on the disk + + **Option A – PCM 24-bit audio** + ```bash + sudo MCM_MEDIA_PROXY_PORT=8002 ffmpeg -re -f mcm_audio \ + -channels 2 \ + -sample_rate 48000 \ + -ptime 1ms \ + -pcm_fmt pcm24 \ + -protocol_type auto \ + -payload_type st30 \ + -ip_addr 192.168.96.1 \ + -port 9001 \ + -i - output.wav + ``` + + **Option B – PCM 16-bit audio** + ```bash + sudo MCM_MEDIA_PROXY_PORT=8002 ffmpeg -re -f mcm_audio \ + -channels 2 \ + -sample_rate 48000 \ + -ptime 1ms \ + -pcm_fmt pcm16 \ + -protocol_type auto \ + -payload_type st30 \ + -ip_addr 192.168.96.1 \ + -port 9001 \ + -i - output.wav + ``` + +### Sender side setup + +1. Start media_proxy + ```bash + sudo media_proxy -d 0000:32:11.0 -i 192.168.96.1 -t 8001 + ``` +2. Start FFmpeg to stream an audio file to the receiver via MCM + + **Option A – PCM 24-bit audio** + ```bash + sudo MCM_MEDIA_PROXY_PORT=8001 ffmpeg -i -f mcm_audio \ + -channels 2 \ + -sample_rate 48000 \ + -ptime 1ms \ + -protocol_type auto \ + -payload_type st30 \ + -ip_addr 192.168.96.2 \ + -port 9001 - + ``` + + **Option B – PCM 16-bit audio** + ```bash + sudo MCM_MEDIA_PROXY_PORT=8001 ffmpeg -i -f mcm_audio_pcm16 \ + -channels 2 \ + -sample_rate 48000 \ + -ptime 1ms \ + -protocol_type auto \ + -payload_type st30 \ + -ip_addr 192.168.96.2 \ + -port 9001 - + ``` + ## Known Issues ### Shared libraries error: diff --git a/ffmpeg-plugin/mcm_audio_rx.c b/ffmpeg-plugin/mcm_audio_rx.c new file mode 100644 index 00000000..5b6e8b6a --- /dev/null +++ b/ffmpeg-plugin/mcm_audio_rx.c @@ -0,0 +1,178 @@ +/* + * SPDX-FileCopyrightText: Copyright (c) 2024 Intel Corporation + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "libavutil/log.h" +#include "libavutil/opt.h" +#include "libavutil/internal.h" +#include "libavformat/avformat.h" +#include "libavformat/mux.h" +#include "libavformat/internal.h" +#include "libavdevice/mcm_common.h" +#include + +typedef struct McmAudioDemuxerContext { + const AVClass *class; /**< Class for private options. */ + + /* arguments */ + char *ip_addr; + char *port; + char *protocol_type; + char *payload_type; + char *socket_name; + int interface_id; + + int channels; + int sample_rate; + char* ptime; + char* pcm_format; + + mcm_conn_context *rx_handle; + bool first_frame; +} McmAudioDemuxerContext; + +static int mcm_audio_read_header(AVFormatContext* avctx) +{ + McmAudioDemuxerContext *s = avctx->priv_data; + mcm_audio_sampling mcm_sample_rate; + mcm_conn_param param = { 0 }; + mcm_audio_ptime mcm_ptime; + mcm_audio_format mcm_fmt; + enum AVCodecID codec_id; + AVStream *st; + int err; + + err = mcm_parse_conn_param(avctx, ¶m, is_rx, s->ip_addr, s->port, + s->protocol_type, s->payload_type, s->socket_name, + s->interface_id); + if (err) + return err; + + /* payload type */ + if (param.payload_type != PAYLOAD_TYPE_ST30_AUDIO) { + av_log(avctx, AV_LOG_ERROR, "Unknown payload type\n"); + return AVERROR(EINVAL); + } + + err = mcm_parse_audio_sample_rate(avctx, &mcm_sample_rate, s->sample_rate); + if (err) + return err; + + err = mcm_parse_audio_packet_time(avctx, &mcm_ptime, s->ptime); + if (err) + return err; + + err = mcm_parse_audio_pcm_format(avctx, &mcm_fmt, &codec_id, s->pcm_format); + if (err) + return err; + + /* audio format */ + param.payload_args.audio_args.type = AUDIO_TYPE_FRAME_LEVEL; + param.payload_args.audio_args.channel = s->channels; + param.payload_args.audio_args.sampling = mcm_sample_rate; + param.payload_args.audio_args.ptime = mcm_ptime; + param.payload_args.audio_args.format = mcm_fmt; + + s->rx_handle = mcm_create_connection(¶m); + if (!s->rx_handle) { + av_log(avctx, AV_LOG_ERROR, "Create connection failed\n"); + return AVERROR(EIO); + } + + st = avformat_new_stream(avctx, NULL); + if (!st) + return AVERROR(ENOMEM); + + avpriv_set_pts_info(st, 64, 1, 1000000); + + st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO; + st->codecpar->codec_id = codec_id; + st->codecpar->ch_layout.nb_channels = s->channels; + st->codecpar->sample_rate = s->sample_rate; + + s->first_frame = true; + + av_log(avctx, AV_LOG_INFO, + "codec:%s sampling:%d ch:%d ptime:%s\n", + avcodec_get_name(codec_id), s->sample_rate, s->channels, s->ptime); + return 0; +} + +static int mcm_audio_read_packet(AVFormatContext* avctx, AVPacket* pkt) +{ + McmAudioDemuxerContext *s = avctx->priv_data; + mcm_buffer *buf = NULL; + int timeout = s->first_frame ? -1 : 1000; + int ret, len, err = 0; + + s->first_frame = false; + + buf = mcm_dequeue_buffer(s->rx_handle, timeout, &err); + if (buf == NULL) { + if (!err) + return AVERROR_EOF; + + av_log(avctx, AV_LOG_ERROR, "Dequeue buffer error %d\n", err); + return AVERROR(EIO); + } + + len = buf->len; + if ((ret = av_new_packet(pkt, len)) < 0) + return ret; + + memcpy(pkt->data, buf->data, len); + + pkt->pts = pkt->dts = AV_NOPTS_VALUE; + + if ((err = mcm_enqueue_buffer(s->rx_handle, buf)) != 0) { + av_log(avctx, AV_LOG_ERROR, "Enqueue buffer error %d\n", err); + return AVERROR(EIO); + } + + return len; +} + +static int mcm_audio_read_close(AVFormatContext* avctx) +{ + McmAudioDemuxerContext* s = avctx->priv_data; + + mcm_destroy_connection(s->rx_handle); + return 0; +} + +#define OFFSET(x) offsetof(McmAudioDemuxerContext, x) +#define DEC (AV_OPT_FLAG_DECODING_PARAM) +static const AVOption mcm_audio_rx_options[] = { + { "ip_addr", "set remote IP address", OFFSET(ip_addr), AV_OPT_TYPE_STRING, {.str = "192.168.96.1"}, .flags = DEC }, + { "port", "set local port", OFFSET(port), AV_OPT_TYPE_STRING, {.str = "9001"}, .flags = DEC }, + { "protocol_type", "set protocol type", OFFSET(protocol_type), AV_OPT_TYPE_STRING, {.str = "auto"}, .flags = DEC }, + { "payload_type", "set payload type", OFFSET(payload_type), AV_OPT_TYPE_STRING, {.str = "st20"}, .flags = DEC }, + { "socket_name", "set memif socket name", OFFSET(socket_name), AV_OPT_TYPE_STRING, {.str = NULL}, .flags = DEC }, + { "interface_id", "set interface id", OFFSET(interface_id), AV_OPT_TYPE_INT, {.i64 = 0}, -1, INT_MAX, DEC }, + { "channels", "number of audio channels", OFFSET(channels), AV_OPT_TYPE_INT, {.i64 = 2}, 1, INT_MAX, DEC }, + { "sample_rate", "audio sample rate", OFFSET(sample_rate), AV_OPT_TYPE_INT, {.i64 = 48000}, 1, INT_MAX, DEC }, + { "ptime", "audio packet time", OFFSET(ptime), AV_OPT_TYPE_STRING, {.str = "1ms"}, .flags = DEC }, + { "pcm_fmt", "audio PCM format", OFFSET(pcm_format), AV_OPT_TYPE_STRING, {.str = "pcm24"}, .flags = DEC }, + { NULL }, +}; + +static const AVClass mcm_audio_demuxer_class = { + .class_name = "mcm audio demuxer", + .item_name = av_default_item_name, + .option = mcm_audio_rx_options, + .version = LIBAVUTIL_VERSION_INT, + .category = AV_CLASS_CATEGORY_DEVICE_AUDIO_INPUT, +}; + +AVInputFormat ff_mcm_audio_demuxer = { + .name = "mcm_audio", + .long_name = NULL_IF_CONFIG_SMALL("Media Communications Mesh audio"), + .priv_data_size = sizeof(McmAudioDemuxerContext), + .read_header = mcm_audio_read_header, + .read_packet = mcm_audio_read_packet, + .read_close = mcm_audio_read_close, + .flags = AVFMT_NOFILE, + .priv_class = &mcm_audio_demuxer_class, +}; diff --git a/ffmpeg-plugin/mcm_audio_tx.c b/ffmpeg-plugin/mcm_audio_tx.c new file mode 100644 index 00000000..9048598d --- /dev/null +++ b/ffmpeg-plugin/mcm_audio_tx.c @@ -0,0 +1,194 @@ +/* + * SPDX-FileCopyrightText: Copyright (c) 2024 Intel Corporation + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "libavutil/log.h" +#include "libavutil/opt.h" +#include "libavutil/internal.h" +#include "libavformat/avformat.h" +#include "libavformat/mux.h" +#include "libavdevice/mcm_common.h" +#include + +typedef struct McmAudioMuxerContext { + const AVClass *class; /**< Class for private options. */ + + /* arguments */ + char *ip_addr; + char *port; + char *protocol_type; + char *payload_type; + char *socket_name; + int interface_id; + + int channels; + int sample_rate; + char* ptime; + + mcm_conn_context *tx_handle; +} McmAudioMuxerContext; + +static int mcm_audio_write_header(AVFormatContext* avctx) +{ + AVCodecParameters* codecpar = avctx->streams[0]->codecpar; + McmAudioMuxerContext *s = avctx->priv_data; + mcm_audio_sampling mcm_sample_rate; + mcm_conn_param param = { 0 }; + mcm_audio_ptime mcm_ptime; + mcm_audio_format mcm_fmt; + int err; + + err = mcm_parse_conn_param(avctx, ¶m, is_tx, s->ip_addr, s->port, + s->protocol_type, s->payload_type, s->socket_name, + s->interface_id); + if (err) + return err; + + /* payload type */ + if (param.payload_type != PAYLOAD_TYPE_ST30_AUDIO) { + av_log(avctx, AV_LOG_ERROR, "Unknown payload type\n"); + return AVERROR(EINVAL); + } + + /* check channels argument */ + if (codecpar->ch_layout.nb_channels != s->channels) { + av_log(avctx, AV_LOG_ERROR, "Source audio stream is of %d channels, not %d\n", + codecpar->ch_layout.nb_channels, s->channels); + return AVERROR(EINVAL); + } + + /* check sample_rate argument */ + if (codecpar->sample_rate != s->sample_rate) { + av_log(avctx, AV_LOG_ERROR, "Source audio stream sample rate is %d, not %d\n", + codecpar->sample_rate, s->sample_rate); + return AVERROR(EINVAL); + } + + err = mcm_parse_audio_sample_rate(avctx, &mcm_sample_rate, s->sample_rate); + if (err) + return err; + + err = mcm_parse_audio_packet_time(avctx, &mcm_ptime, s->ptime); + if (err) + return err; + + switch (codecpar->codec_id) { + case AV_CODEC_ID_PCM_S24BE: + mcm_fmt = AUDIO_FMT_PCM24; + break; + case AV_CODEC_ID_PCM_S16BE: + mcm_fmt = AUDIO_FMT_PCM16; + break; + default: + av_log(avctx, AV_LOG_ERROR, "Audio PCM format not supported\n"); + return AVERROR(EINVAL); + } + + /* audio format */ + param.payload_args.audio_args.type = AUDIO_TYPE_FRAME_LEVEL; + param.payload_args.audio_args.channel = s->channels; + param.payload_args.audio_args.sampling = mcm_sample_rate; + param.payload_args.audio_args.ptime = mcm_ptime; + param.payload_args.audio_args.format = mcm_fmt; + + s->tx_handle = mcm_create_connection(¶m); + if (!s->tx_handle) { + av_log(avctx, AV_LOG_ERROR, "Create connection failed\n"); + return AVERROR(EIO); + } + + av_log(avctx, AV_LOG_INFO, "codec:%s sampling:%d ch:%d ptime:%s\n", + avcodec_get_name(codecpar->codec_id), s->sample_rate, s->channels, + s->ptime); + return 0; +} + +static int mcm_audio_write_packet(AVFormatContext* avctx, AVPacket* pkt) +{ + McmAudioMuxerContext *s = avctx->priv_data; + const uint8_t *data = pkt->data; + mcm_buffer *buf = NULL; + int size = pkt->size; + int len, err = 0; + + while (size > 0) { + buf = mcm_dequeue_buffer(s->tx_handle, -1, &err); + if (buf == NULL) { + av_log(avctx, AV_LOG_ERROR, "Dequeue buffer error %d\n", err); + return AVERROR(EIO); + } + + len = FFMIN(buf->len, size); + memcpy(buf->data, data, len); + data += len; + size -= len; + + buf->len = len; + + if ((err = mcm_enqueue_buffer(s->tx_handle, buf)) != 0) { + av_log(avctx, AV_LOG_ERROR, "Enqueue buffer error %d\n", err); + return AVERROR(EIO); + } + } + + return 0; +} + +static int mcm_audio_write_trailer(AVFormatContext* avctx) +{ + McmAudioMuxerContext *s = avctx->priv_data; + + mcm_destroy_connection(s->tx_handle); + return 0; +} + +#define OFFSET(x) offsetof(McmAudioMuxerContext, x) +#define ENC AV_OPT_FLAG_ENCODING_PARAM +static const AVOption mcm_audio_tx_options[] = { + { "ip_addr", "set remote IP address", OFFSET(ip_addr), AV_OPT_TYPE_STRING, {.str = "192.168.96.2"}, .flags = ENC }, + { "port", "set remote port", OFFSET(port), AV_OPT_TYPE_STRING, {.str = "9001"}, .flags = ENC }, + { "protocol_type", "set protocol type", OFFSET(protocol_type), AV_OPT_TYPE_STRING, {.str = "auto"}, .flags = ENC }, + { "payload_type", "set payload type", OFFSET(payload_type), AV_OPT_TYPE_STRING, {.str = "st30"}, .flags = ENC }, + { "socket_name", "set memif socket name", OFFSET(socket_name), AV_OPT_TYPE_STRING, {.str = NULL}, .flags = ENC }, + { "interface_id", "set interface id", OFFSET(interface_id), AV_OPT_TYPE_INT, {.i64 = 0}, -1, INT_MAX, ENC }, + { "channels", "number of audio channels", OFFSET(channels), AV_OPT_TYPE_INT, {.i64 = 2}, 1, INT_MAX, ENC }, + { "sample_rate", "audio sample rate", OFFSET(sample_rate), AV_OPT_TYPE_INT, {.i64 = 48000}, 1, INT_MAX, ENC }, + { "ptime", "audio packet time", OFFSET(ptime), AV_OPT_TYPE_STRING, {.str = "1ms"}, .flags = ENC }, + { NULL }, +}; + +static const AVClass mcm_audio_muxer_class = { + .class_name = "mcm audio muxer", + .item_name = av_default_item_name, + .option = mcm_audio_tx_options, + .version = LIBAVUTIL_VERSION_INT, + .category = AV_CLASS_CATEGORY_DEVICE_AUDIO_OUTPUT, +}; + +const FFOutputFormat ff_mcm_audio_muxer = { + .p.name = "mcm_audio", + .p.long_name = NULL_IF_CONFIG_SMALL("Media Communications Mesh audio pcm24"), + .priv_data_size = sizeof(McmAudioMuxerContext), + .write_header = mcm_audio_write_header, + .write_packet = mcm_audio_write_packet, + .write_trailer = mcm_audio_write_trailer, + .p.audio_codec = AV_CODEC_ID_PCM_S24BE, + .p.video_codec = AV_CODEC_ID_NONE, + .p.flags = AVFMT_NOFILE, + .p.priv_class = &mcm_audio_muxer_class, +}; + +const FFOutputFormat ff_mcm_audio_pcm16_muxer = { + .p.name = "mcm_audio_pcm16", + .p.long_name = NULL_IF_CONFIG_SMALL("Media Communications Mesh audio pcm16"), + .priv_data_size = sizeof(McmAudioMuxerContext), + .write_header = mcm_audio_write_header, + .write_packet = mcm_audio_write_packet, + .write_trailer = mcm_audio_write_trailer, + .p.audio_codec = AV_CODEC_ID_PCM_S16BE, + .p.video_codec = AV_CODEC_ID_NONE, + .p.flags = AVFMT_NOFILE, + .p.priv_class = &mcm_audio_muxer_class, +}; diff --git a/ffmpeg-plugin/mcm_common.c b/ffmpeg-plugin/mcm_common.c new file mode 100644 index 00000000..5b764e7f --- /dev/null +++ b/ffmpeg-plugin/mcm_common.c @@ -0,0 +1,118 @@ +/* + * SPDX-FileCopyrightText: Copyright (c) 2024 Intel Corporation + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "mcm_common.h" +#include + +/* Parse MCM connection parameters and fill the structure */ +int mcm_parse_conn_param(AVFormatContext* avctx, mcm_conn_param *param, + transfer_type type, char *ip_addr, char *port, + char *protocol_type, char *payload_type, + char *socket_name, int interface_id) +{ + param->type = type; + + strlcpy(param->remote_addr.ip, ip_addr, sizeof(param->remote_addr.ip)); + + if (type == is_tx) + strlcpy(param->remote_addr.port, port, sizeof(param->remote_addr.port)); + else + strlcpy(param->local_addr.port, port, sizeof(param->local_addr.port)); + + /* protocol type */ + if (!strcmp(protocol_type, "memif")) { + param->protocol = PROTO_MEMIF; + snprintf(param->memif_interface.socket_path, sizeof(param->memif_interface.socket_path), + "/run/mcm/mcm_memif_%s.sock", socket_name ? socket_name : "0"); + param->memif_interface.interface_id = interface_id; + param->memif_interface.is_master = (type == is_tx) ? 1 : 0; + } else if (!strcmp(protocol_type, "udp")) { + param->protocol = PROTO_UDP; + } else if (!strcmp(protocol_type, "tcp")) { + param->protocol = PROTO_TCP; + } else if (!strcmp(protocol_type, "http")) { + param->protocol = PROTO_HTTP; + } else if (!strcmp(protocol_type, "grpc")) { + param->protocol = PROTO_GRPC; + } else { + param->protocol = PROTO_AUTO; + } + + /* payload type */ + if (!strcmp(payload_type, "st20")) { + param->payload_type = PAYLOAD_TYPE_ST20_VIDEO; + } else if (!strcmp(payload_type, "st22")) { + param->payload_type = PAYLOAD_TYPE_ST22_VIDEO; + param->payload_codec = PAYLOAD_CODEC_JPEGXS; + } else if (!strcmp(payload_type, "st30")) { + param->payload_type = PAYLOAD_TYPE_ST30_AUDIO; + } else if (!strcmp(payload_type, "st40")) { + param->payload_type = PAYLOAD_TYPE_ST40_ANCILLARY; + } else if (!strcmp(payload_type, "rtsp")) { + param->payload_type = PAYLOAD_TYPE_RTSP_VIDEO; + } else { + av_log(avctx, AV_LOG_ERROR, "Unknown payload type\n"); + return AVERROR(EINVAL); + } + + return 0; +} + +/* Parse MCM audio sampling rate */ +int mcm_parse_audio_sample_rate(AVFormatContext* avctx, mcm_audio_sampling *sample_rate, + int value) +{ + switch (value) { + case 44100: + *sample_rate = AUDIO_SAMPLING_44K; + return 0; + case 48000: + *sample_rate = AUDIO_SAMPLING_48K; + return 0; + case 96000: + *sample_rate = AUDIO_SAMPLING_96K; + return 0; + default: + av_log(avctx, AV_LOG_ERROR, "Audio sample rate not supported\n"); + return AVERROR(EINVAL); + } +} + +/* Parse MCM audio packet time */ +int mcm_parse_audio_packet_time(AVFormatContext* avctx, mcm_audio_ptime *ptime, + char *str) +{ + if (!str || !strcmp(str, "1ms")) { + *ptime = AUDIO_PTIME_1MS; + return 0; + } + if (!strcmp(str, "125us")) { + *ptime = AUDIO_PTIME_125US; + return 0; + } + + av_log(avctx, AV_LOG_ERROR, "Audio packet time not supported\n"); + return AVERROR(EINVAL); +} + +/* Parse MCM audio PCM format and codec id */ +int mcm_parse_audio_pcm_format(AVFormatContext* avctx, mcm_audio_format *fmt, + enum AVCodecID *codec_id, char *str) +{ + if (!str || !strcmp(str, "pcm24")) { + *fmt = AUDIO_FMT_PCM24; + *codec_id = AV_CODEC_ID_PCM_S24BE; + return 0; + } + if (!strcmp(str, "pcm16")) { + *fmt = AUDIO_FMT_PCM16; + *codec_id = AV_CODEC_ID_PCM_S16BE; + return 0; + } + + av_log(avctx, AV_LOG_ERROR, "Audio PCM format not supported\n"); + return AVERROR(EINVAL); +} diff --git a/ffmpeg-plugin/mcm_common.h b/ffmpeg-plugin/mcm_common.h new file mode 100644 index 00000000..fb3a7160 --- /dev/null +++ b/ffmpeg-plugin/mcm_common.h @@ -0,0 +1,32 @@ +/* + * SPDX-FileCopyrightText: Copyright (c) 2024 Intel Corporation + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef __MCM_COMMON_H__ +#define __MCM_COMMON_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "libavformat/avformat.h" +#include + +int mcm_parse_conn_param(AVFormatContext* avctx, mcm_conn_param *param, + transfer_type type, char *ip_addr, char *port, + char *protocol_type, char *payload_type, + char *socket_name, int interface_id); +int mcm_parse_audio_sample_rate(AVFormatContext* avctx, mcm_audio_sampling *sample_rate, + int value); +int mcm_parse_audio_packet_time(AVFormatContext* avctx, mcm_audio_ptime *ptime, + char *str); +int mcm_parse_audio_pcm_format(AVFormatContext* avctx, mcm_audio_format *fmt, + enum AVCodecID *codec_id, char *str); + +#ifdef __cplusplus +} +#endif + +#endif /* __MCM_COMMON_H__ */ diff --git a/ffmpeg-plugin/mcm_rx.c b/ffmpeg-plugin/mcm_video_rx.c similarity index 64% rename from ffmpeg-plugin/mcm_rx.c rename to ffmpeg-plugin/mcm_video_rx.c index f60b31e8..80d38449 100644 --- a/ffmpeg-plugin/mcm_rx.c +++ b/ffmpeg-plugin/mcm_video_rx.c @@ -1,3 +1,9 @@ +/* + * SPDX-FileCopyrightText: Copyright (c) 2024 Intel Corporation + * + * SPDX-License-Identifier: BSD-3-Clause + */ + #include "libavutil/log.h" #include "libavutil/opt.h" #include "libavutil/internal.h" @@ -5,28 +11,29 @@ #include "libavformat/avformat.h" #include "libavformat/mux.h" #include "libavformat/internal.h" +#include "libavdevice/mcm_common.h" #include -#include -typedef struct McmDemuxerContext { +typedef struct McmVideoDemuxerContext { const AVClass *class; /**< Class for private options. */ /* arguments */ char *ip_addr; char *port; - char *payload_type; char *protocol_type; + char *payload_type; + char *socket_name; + int interface_id; + int width; int height; enum AVPixelFormat pixel_format; AVRational frame_rate; - char *socket_name; - int interface_id; mcm_conn_context *rx_handle; bool first_frame; int frame_size; -} McmDemuxerContext; +} McmVideoDemuxerContext; static int getFrameSize(video_pixel_format fmt, uint32_t width, uint32_t height, bool interlaced) { @@ -57,74 +64,23 @@ transport frame without conversion. The frame should not have lines padding) */ return (int)size; } -static int mcm_read_header(AVFormatContext* avctx) +static int mcm_video_read_header(AVFormatContext* avctx) { - McmDemuxerContext *s = avctx->priv_data; + McmVideoDemuxerContext *s = avctx->priv_data; mcm_conn_param param = { 0 }; AVStream *st; + int err; - strlcpy(param.remote_addr.ip, s->ip_addr, sizeof(param.remote_addr.ip)); - strlcpy(param.local_addr.port, s->port, sizeof(param.local_addr.port)); - - /* protocol type */ - if (strcmp(s->protocol_type, "memif") == 0) { - param.protocol = PROTO_MEMIF; - param.memif_interface.is_master = 0; - snprintf(param.memif_interface.socket_path, sizeof(param.memif_interface.socket_path), - "/run/mcm/mcm_memif_%s.sock", s->socket_name ? s->socket_name : "0"); - param.memif_interface.interface_id = s->interface_id; - } else if (strcmp(s->protocol_type, "udp") == 0) { - param.protocol = PROTO_UDP; - } else if (strcmp(s->protocol_type, "tcp") == 0) { - param.protocol = PROTO_TCP; - } else if (strcmp(s->protocol_type, "http") == 0) { - param.protocol = PROTO_HTTP; - } else if (strcmp(s->protocol_type, "grpc") == 0) { - param.protocol = PROTO_GRPC; - } else { - param.protocol = PROTO_AUTO; - } - - /* payload type */ - if (strcmp(s->payload_type, "st20") == 0) { - param.payload_type = PAYLOAD_TYPE_ST20_VIDEO; - } else if (strcmp(s->payload_type, "st22") == 0) { - param.payload_type = PAYLOAD_TYPE_ST22_VIDEO; - param.payload_codec = PAYLOAD_CODEC_JPEGXS; - } else if (strcmp(s->payload_type, "st30") == 0) { - param.payload_type = PAYLOAD_TYPE_ST30_AUDIO; - } else if (strcmp(s->payload_type, "st40") == 0) { - param.payload_type = PAYLOAD_TYPE_ST40_ANCILLARY; - } else if (strcmp(s->payload_type, "rtsp") == 0) { - param.payload_type = PAYLOAD_TYPE_RTSP_VIDEO; - } else { - av_log(avctx, AV_LOG_ERROR, "unknown payload type\n"); - return AVERROR(EINVAL); - } + err = mcm_parse_conn_param(avctx, ¶m, is_rx, s->ip_addr, s->port, + s->protocol_type, s->payload_type, s->socket_name, + s->interface_id); + if (err) + return err; switch (param.payload_type) { - case PAYLOAD_TYPE_ST30_AUDIO: - /* audio format */ - // param.payload_args.audio_args.type = AUDIO_TYPE_FRAME_LEVEL; - // param.payload_args.audio_args.channel = 2; - // param.payload_args.audio_args.format = AUDIO_FMT_PCM16; - // param.payload_args.audio_args.sampling = AUDIO_SAMPLING_48K; - // param.payload_args.audio_args.ptime = AUDIO_PTIME_1MS; - av_log(avctx, AV_LOG_ERROR, "payload type st30 is not yet supported\n"); - return AVERROR(EINVAL); // not supported yet - - case PAYLOAD_TYPE_ST40_ANCILLARY: - /* ancillary format */ - // param.payload_args.anc_args.format = ANC_FORMAT_CLOSED_CAPTION; - // param.payload_args.anc_args.type = ANC_TYPE_FRAME_LEVEL; - // param.payload_args.anc_args.fps = av_q2d(s->frame_rate); - av_log(avctx, AV_LOG_ERROR, "payload type st40 is not yet supported\n"); - return AVERROR(EINVAL); // not supported yet - case PAYLOAD_TYPE_RTSP_VIDEO: case PAYLOAD_TYPE_ST20_VIDEO: case PAYLOAD_TYPE_ST22_VIDEO: - default: /* video format */ param.payload_args.video_args.width = param.width = s->width; param.payload_args.video_args.height = param.height = s->height; @@ -150,9 +106,11 @@ static int mcm_read_header(AVFormatContext* avctx) param.payload_args.video_args.pix_fmt = param.pix_fmt; break; - } - param.type = is_rx; + default: + av_log(avctx, AV_LOG_ERROR, "Unknown payload type\n"); + return AVERROR(EINVAL); + } s->frame_size = getFrameSize(param.pix_fmt, s->width, s->height, false); if (s->frame_size <= 0) { @@ -187,9 +145,9 @@ static int mcm_read_header(AVFormatContext* avctx) return 0; } -static int mcm_read_packet(AVFormatContext* avctx, AVPacket* pkt) +static int mcm_video_read_packet(AVFormatContext* avctx, AVPacket* pkt) { - McmDemuxerContext *s = avctx->priv_data; + McmVideoDemuxerContext *s = avctx->priv_data; mcm_buffer *buf = NULL; int timeout = s->first_frame ? -1 : 1000; int err = 0; @@ -221,46 +179,46 @@ static int mcm_read_packet(AVFormatContext* avctx, AVPacket* pkt) return s->frame_size; } -static int mcm_read_close(AVFormatContext* avctx) +static int mcm_video_read_close(AVFormatContext* avctx) { - McmDemuxerContext* s = avctx->priv_data; + McmVideoDemuxerContext* s = avctx->priv_data; mcm_destroy_connection(s->rx_handle); return 0; } -#define OFFSET(x) offsetof(McmDemuxerContext, x) +#define OFFSET(x) offsetof(McmVideoDemuxerContext, x) #define DEC (AV_OPT_FLAG_DECODING_PARAM) -static const AVOption mcm_rx_options[] = { +static const AVOption mcm_video_rx_options[] = { { "ip_addr", "set remote IP address", OFFSET(ip_addr), AV_OPT_TYPE_STRING, {.str = "192.168.96.1"}, .flags = DEC }, { "port", "set local port", OFFSET(port), AV_OPT_TYPE_STRING, {.str = "9001"}, .flags = DEC }, - { "payload_type", "set payload type", OFFSET(payload_type), AV_OPT_TYPE_STRING, {.str = "st20"}, .flags = DEC }, { "protocol_type", "set protocol type", OFFSET(protocol_type), AV_OPT_TYPE_STRING, {.str = "auto"}, .flags = DEC }, + { "payload_type", "set payload type", OFFSET(payload_type), AV_OPT_TYPE_STRING, {.str = "st20"}, .flags = DEC }, + { "socket_name", "set memif socket name", OFFSET(socket_name), AV_OPT_TYPE_STRING, {.str = NULL}, .flags = DEC }, + { "interface_id", "set interface id", OFFSET(interface_id), AV_OPT_TYPE_INT, {.i64 = 0}, -1, INT_MAX, DEC }, { "video_size", "set video frame size given a string such as 640x480 or hd720", OFFSET(width), AV_OPT_TYPE_IMAGE_SIZE, {.str = "1920x1080"}, 0, 0, DEC }, { "pixel_format", "set video pixel format", OFFSET(pixel_format), AV_OPT_TYPE_PIXEL_FMT, {.i64 = AV_PIX_FMT_YUV422P10LE}, AV_PIX_FMT_NONE, INT_MAX, DEC }, { "frame_rate", "set video frame rate", OFFSET(frame_rate), AV_OPT_TYPE_VIDEO_RATE, {.str = "25"}, 0, INT_MAX, DEC }, - { "socket_name", "set memif socket name", OFFSET(socket_name), AV_OPT_TYPE_STRING, {.str = NULL}, .flags = DEC }, - { "interface_id", "set interface ID", OFFSET(interface_id), AV_OPT_TYPE_INT, {.i64 = 0}, -1, INT_MAX, DEC }, { NULL }, }; -static const AVClass mcm_demuxer_class = { - .class_name = "mcm demuxer", +static const AVClass mcm_video_demuxer_class = { + .class_name = "mcm video demuxer", .item_name = av_default_item_name, - .option = mcm_rx_options, + .option = mcm_video_rx_options, .version = LIBAVUTIL_VERSION_INT, .category = AV_CLASS_CATEGORY_DEVICE_INPUT, }; AVInputFormat ff_mcm_demuxer = { .name = "mcm", - .long_name = NULL_IF_CONFIG_SMALL("Media Communications Mesh"), - .priv_data_size = sizeof(McmDemuxerContext), - .read_header = mcm_read_header, - .read_packet = mcm_read_packet, - .read_close = mcm_read_close, + .long_name = NULL_IF_CONFIG_SMALL("Media Communications Mesh video"), + .priv_data_size = sizeof(McmVideoDemuxerContext), + .read_header = mcm_video_read_header, + .read_packet = mcm_video_read_packet, + .read_close = mcm_video_read_close, .flags = AVFMT_NOFILE, .extensions = "mcm", .raw_codec_id = AV_CODEC_ID_RAWVIDEO, - .priv_class = &mcm_demuxer_class, + .priv_class = &mcm_video_demuxer_class, }; diff --git a/ffmpeg-plugin/mcm_tx.c b/ffmpeg-plugin/mcm_video_tx.c similarity index 51% rename from ffmpeg-plugin/mcm_tx.c rename to ffmpeg-plugin/mcm_video_tx.c index 5ea9d322..acc46ba4 100644 --- a/ffmpeg-plugin/mcm_tx.c +++ b/ffmpeg-plugin/mcm_video_tx.c @@ -1,97 +1,53 @@ +/* + * SPDX-FileCopyrightText: Copyright (c) 2024 Intel Corporation + * + * SPDX-License-Identifier: BSD-3-Clause + */ + #include "libavutil/log.h" #include "libavutil/opt.h" #include "libavutil/internal.h" #include "libavutil/pixdesc.h" #include "libavformat/avformat.h" #include "libavformat/mux.h" +#include "libavdevice/mcm_common.h" #include -#include -typedef struct McmMuxerContext { +typedef struct McmVideoMuxerContext { const AVClass *class; /**< Class for private options. */ /* arguments */ char *ip_addr; char *port; - char *payload_type; char *protocol_type; + char *payload_type; + char *socket_name; + int interface_id; + int width; int height; enum AVPixelFormat pixel_format; AVRational frame_rate; - char *socket_name; - int interface_id; mcm_conn_context *tx_handle; -} McmMuxerContext; +} McmVideoMuxerContext; -static int mcm_write_header(AVFormatContext* avctx) +static int mcm_video_write_header(AVFormatContext* avctx) { - McmMuxerContext *s = avctx->priv_data; + McmVideoMuxerContext *s = avctx->priv_data; mcm_conn_param param = { 0 }; + int err; - strlcpy(param.remote_addr.ip, s->ip_addr, sizeof(param.remote_addr.ip)); - strlcpy(param.remote_addr.port, s->port, sizeof(param.remote_addr.port)); - - /* protocol type */ - if (strcmp(s->protocol_type, "memif") == 0) { - param.protocol = PROTO_MEMIF; - param.memif_interface.is_master = 1; - snprintf(param.memif_interface.socket_path, sizeof(param.memif_interface.socket_path), - "/run/mcm/mcm_memif_%s.sock", s->socket_name ? s->socket_name : "0"); - param.memif_interface.interface_id = s->interface_id; - } else if (strcmp(s->protocol_type, "udp") == 0) { - param.protocol = PROTO_UDP; - } else if (strcmp(s->protocol_type, "tcp") == 0) { - param.protocol = PROTO_TCP; - } else if (strcmp(s->protocol_type, "http") == 0) { - param.protocol = PROTO_HTTP; - } else if (strcmp(s->protocol_type, "grpc") == 0) { - param.protocol = PROTO_GRPC; - } else { - param.protocol = PROTO_AUTO; - } - - /* payload type */ - if (strcmp(s->payload_type, "st20") == 0) { - param.payload_type = PAYLOAD_TYPE_ST20_VIDEO; - } else if (strcmp(s->payload_type, "st22") == 0) { - param.payload_type = PAYLOAD_TYPE_ST22_VIDEO; - param.payload_codec = PAYLOAD_CODEC_JPEGXS; - } else if (strcmp(s->payload_type, "st30") == 0) { - param.payload_type = PAYLOAD_TYPE_ST30_AUDIO; - } else if (strcmp(s->payload_type, "st40") == 0) { - param.payload_type = PAYLOAD_TYPE_ST40_ANCILLARY; - } else if (strcmp(s->payload_type, "rtsp") == 0) { - param.payload_type = PAYLOAD_TYPE_RTSP_VIDEO; - } else { - av_log(NULL, AV_LOG_ERROR, "Unknown payload type\n"); - return AVERROR(EINVAL); - } + err = mcm_parse_conn_param(avctx, ¶m, is_tx, s->ip_addr, s->port, + s->protocol_type, s->payload_type, s->socket_name, + s->interface_id); + if (err) + return err; switch (param.payload_type) { - case PAYLOAD_TYPE_ST30_AUDIO: - /* audio format */ - // param.payload_args.audio_args.type = AUDIO_TYPE_FRAME_LEVEL; - // param.payload_args.audio_args.channel = 2; - // param.payload_args.audio_args.format = AUDIO_FMT_PCM16; - // param.payload_args.audio_args.sampling = AUDIO_SAMPLING_48K; - // param.payload_args.audio_args.ptime = AUDIO_PTIME_1MS; - av_log(NULL, AV_LOG_ERROR, "Payload type st30 is not yet supported\n"); - return AVERROR(EINVAL); // not supported yet - - case PAYLOAD_TYPE_ST40_ANCILLARY: - /* ancillary format */ - // param.payload_args.anc_args.format = ANC_FORMAT_CLOSED_CAPTION; - // param.payload_args.anc_args.type = ANC_TYPE_FRAME_LEVEL; - // param.payload_args.anc_args.fps = av_q2d(s->frame_rate); - av_log(NULL, AV_LOG_ERROR, "Payload type st40 is not yet supported\n"); - return AVERROR(EINVAL); // not supported yet - case PAYLOAD_TYPE_RTSP_VIDEO: case PAYLOAD_TYPE_ST20_VIDEO: case PAYLOAD_TYPE_ST22_VIDEO: - default: /* video format */ param.payload_args.video_args.width = param.width = s->width; param.payload_args.video_args.height = param.height = s->height; @@ -117,13 +73,15 @@ static int mcm_write_header(AVFormatContext* avctx) param.payload_args.video_args.pix_fmt = param.pix_fmt; break; - } - param.type = is_tx; + default: + av_log(avctx, AV_LOG_ERROR, "Unknown payload type\n"); + return AVERROR(EINVAL); + } s->tx_handle = mcm_create_connection(¶m); if (!s->tx_handle) { - av_log(avctx, AV_LOG_ERROR, "create connection failed\n"); + av_log(avctx, AV_LOG_ERROR, "Create connection failed\n"); return AVERROR(EIO); } @@ -134,67 +92,67 @@ static int mcm_write_header(AVFormatContext* avctx) return 0; } -static int mcm_write_packet(AVFormatContext* avctx, AVPacket* pkt) +static int mcm_video_write_packet(AVFormatContext* avctx, AVPacket* pkt) { - McmMuxerContext *s = avctx->priv_data; + McmVideoMuxerContext *s = avctx->priv_data; mcm_buffer *buf = NULL; int err = 0; buf = mcm_dequeue_buffer(s->tx_handle, -1, &err); if (buf == NULL) { - av_log(avctx, AV_LOG_ERROR, "dequeue buffer error %d\n", err); + av_log(avctx, AV_LOG_ERROR, "Dequeue buffer error %d\n", err); return AVERROR(EIO); } memcpy(buf->data, pkt->data, pkt->size <= buf->len ? pkt->size : buf->len); if ((err = mcm_enqueue_buffer(s->tx_handle, buf)) != 0) { - av_log(avctx, AV_LOG_ERROR, "enqueue buffer error %d\n", err); + av_log(avctx, AV_LOG_ERROR, "Enqueue buffer error %d\n", err); return AVERROR(EIO); } return 0; } -static int mcm_write_trailer(AVFormatContext* avctx) +static int mcm_video_write_trailer(AVFormatContext* avctx) { - McmMuxerContext *s = avctx->priv_data; + McmVideoMuxerContext *s = avctx->priv_data; mcm_destroy_connection(s->tx_handle); return 0; } -#define OFFSET(x) offsetof(McmMuxerContext, x) +#define OFFSET(x) offsetof(McmVideoMuxerContext, x) #define ENC AV_OPT_FLAG_ENCODING_PARAM -static const AVOption mcm_tx_options[] = { +static const AVOption mcm_video_tx_options[] = { { "ip_addr", "set remote IP address", OFFSET(ip_addr), AV_OPT_TYPE_STRING, {.str = "192.168.96.2"}, .flags = ENC }, { "port", "set remote port", OFFSET(port), AV_OPT_TYPE_STRING, {.str = "9001"}, .flags = ENC }, - { "payload_type", "set payload type", OFFSET(payload_type), AV_OPT_TYPE_STRING, {.str = "st20"}, .flags = ENC }, { "protocol_type", "set protocol type", OFFSET(protocol_type), AV_OPT_TYPE_STRING, {.str = "auto"}, .flags = ENC }, + { "payload_type", "set payload type", OFFSET(payload_type), AV_OPT_TYPE_STRING, {.str = "st20"}, .flags = ENC }, + { "socket_name", "set memif socket name", OFFSET(socket_name), AV_OPT_TYPE_STRING, {.str = NULL}, .flags = ENC }, + { "interface_id", "set interface id", OFFSET(interface_id), AV_OPT_TYPE_INT, {.i64 = 0}, -1, INT_MAX, ENC }, { "video_size", "set video frame size given a string such as 640x480 or hd720", OFFSET(width), AV_OPT_TYPE_IMAGE_SIZE, {.str = "1920x1080"}, 0, 0, ENC }, { "pixel_format", "set video pixel format", OFFSET(pixel_format), AV_OPT_TYPE_PIXEL_FMT, {.i64 = AV_PIX_FMT_YUV422P10LE}, AV_PIX_FMT_NONE, INT_MAX, ENC }, { "frame_rate", "set video frame rate", OFFSET(frame_rate), AV_OPT_TYPE_VIDEO_RATE, {.str = "25"}, 0, INT_MAX, ENC }, - { "socket_name", "set memif socket name", OFFSET(socket_name), AV_OPT_TYPE_STRING, {.str = NULL}, .flags = ENC }, - { "interface_id", "set interface ID", OFFSET(interface_id), AV_OPT_TYPE_INT, {.i64 = 0}, -1, INT_MAX, ENC }, { NULL }, }; -static const AVClass mcm_muxer_class = { - .class_name = "mcm muxer", +static const AVClass mcm_video_muxer_class = { + .class_name = "mcm video muxer", .item_name = av_default_item_name, - .option = mcm_tx_options, + .option = mcm_video_tx_options, .version = LIBAVUTIL_VERSION_INT, .category = AV_CLASS_CATEGORY_DEVICE_OUTPUT, }; const FFOutputFormat ff_mcm_muxer = { .p.name = "mcm", - .p.long_name = NULL_IF_CONFIG_SMALL("Media Communications Mesh"), - .priv_data_size = sizeof(McmMuxerContext), - .write_header = mcm_write_header, - .write_packet = mcm_write_packet, - .write_trailer = mcm_write_trailer, + .p.long_name = NULL_IF_CONFIG_SMALL("Media Communications Mesh video"), + .priv_data_size = sizeof(McmVideoMuxerContext), + .write_header = mcm_video_write_header, + .write_packet = mcm_video_write_packet, + .write_trailer = mcm_video_write_trailer, .p.video_codec = AV_CODEC_ID_RAWVIDEO, .p.flags = AVFMT_NOFILE, - .p.priv_class = &mcm_muxer_class, + .p.priv_class = &mcm_video_muxer_class, }; diff --git a/sdk/src/memif_impl.c b/sdk/src/memif_impl.c index 91ed0ad9..7f5f870b 100644 --- a/sdk/src/memif_impl.c +++ b/sdk/src/memif_impl.c @@ -381,7 +381,7 @@ mcm_buffer* memif_dequeue_buffer(mcm_conn_context* conn_ctx, int timeout, int* e } else { if (memif_conn->buf_num > 0) { buf = calloc(1, sizeof(mcm_buffer)); - buf->len = conn_ctx->frame_size; + buf->len = memif_conn->working_bufs[memif_conn->working_idx].len; buf->data = memif_conn->working_bufs[memif_conn->working_idx].data; memif_conn->working_idx++; memif_conn->buf_num--; @@ -423,6 +423,9 @@ int memif_enqueue_buffer(mcm_conn_context* conn_ctx, mcm_buffer* buf) return -1; } + /* set the actual size of data in the buffer */ + if (buf->len < memif_conn->working_bufs[0].len) + memif_conn->working_bufs[0].len = buf->len; err = memif_tx_burst(memif_conn->conn, memif_conn->qid, &memif_conn->working_bufs[0], 1, &buf_num); if (err != MEMIF_ERR_SUCCESS) {