FFmpeg
libndi_newtek_enc.c
Go to the documentation of this file.
1 /*
2  * NewTek NDI output
3  * Copyright (c) 2017 Maksym Veremeyenko
4  *
5  * This file is part of FFmpeg.
6  *
7  * FFmpeg is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * FFmpeg is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with FFmpeg; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20  */
21 
22 #include "libavformat/avformat.h"
23 #include "libavformat/internal.h"
24 #include "libavutil/opt.h"
25 #include "libavutil/imgutils.h"
26 
27 #include "libndi_newtek_common.h"
28 
29 struct NDIContext {
30  const AVClass *cclass;
31 
32  /* Options */
35 
36  NDIlib_video_frame_t *video;
37  NDIlib_audio_frame_interleaved_16s_t *audio;
38  NDIlib_send_instance_t ndi_send;
40 };
41 
43 {
44  struct NDIContext *ctx = avctx->priv_data;
45 
46  if (ctx->ndi_send) {
47  NDIlib_send_destroy(ctx->ndi_send);
49  }
50 
51  av_freep(&ctx->video);
52  av_freep(&ctx->audio);
53 
54  return 0;
55 }
56 
58 {
59  struct NDIContext *ctx = avctx->priv_data;
60  AVFrame *avframe, *tmp = (AVFrame *)pkt->data;
61 
62  if (tmp->format != AV_PIX_FMT_UYVY422 && tmp->format != AV_PIX_FMT_BGRA &&
63  tmp->format != AV_PIX_FMT_BGR0 && tmp->format != AV_PIX_FMT_RGBA &&
64  tmp->format != AV_PIX_FMT_RGB0) {
65  av_log(avctx, AV_LOG_ERROR, "Got a frame with invalid pixel format.\n");
66  return AVERROR(EINVAL);
67  }
68 
69  if (tmp->linesize[0] < 0) {
70  av_log(avctx, AV_LOG_ERROR, "Got a frame with negative linesize.\n");
71  return AVERROR(EINVAL);
72  }
73 
74  if (tmp->width != ctx->video->xres ||
75  tmp->height != ctx->video->yres) {
76  av_log(avctx, AV_LOG_ERROR, "Got a frame with invalid dimension.\n");
77  av_log(avctx, AV_LOG_ERROR, "tmp->width=%d, tmp->height=%d, ctx->video->xres=%d, ctx->video->yres=%d\n",
78  tmp->width, tmp->height, ctx->video->xres, ctx->video->yres);
79  return AVERROR(EINVAL);
80  }
81 
82  avframe = av_frame_clone(tmp);
83  if (!avframe)
84  return AVERROR(ENOMEM);
85 
86  ctx->video->timecode = av_rescale_q(pkt->pts, st->time_base, NDI_TIME_BASE_Q);
87 
88  ctx->video->line_stride_in_bytes = avframe->linesize[0];
89  ctx->video->p_data = (void *)(avframe->data[0]);
90 
91  av_log(avctx, AV_LOG_DEBUG, "%s: pkt->pts=%"PRId64", timecode=%"PRId64", st->time_base=%d/%d\n",
92  __func__, pkt->pts, ctx->video->timecode, st->time_base.num, st->time_base.den);
93 
94  /* asynchronous for one frame, but will block if a second frame
95  is given before the first one has been sent */
96  NDIlib_send_send_video_async(ctx->ndi_send, ctx->video);
97 
99  ctx->last_avframe = avframe;
100 
101  return 0;
102 }
103 
105 {
106  struct NDIContext *ctx = avctx->priv_data;
107 
108  ctx->audio->p_data = (short *)pkt->data;
109  ctx->audio->timecode = av_rescale_q(pkt->pts, st->time_base, NDI_TIME_BASE_Q);
110  ctx->audio->no_samples = pkt->size / (ctx->audio->no_channels << 1);
111 
112  av_log(avctx, AV_LOG_DEBUG, "%s: pkt->pts=%"PRId64", timecode=%"PRId64", st->time_base=%d/%d\n",
113  __func__, pkt->pts, ctx->audio->timecode, st->time_base.num, st->time_base.den);
114 
115  NDIlib_util_send_send_audio_interleaved_16s(ctx->ndi_send, ctx->audio);
116 
117  return 0;
118 }
119 
121 {
122  AVStream *st = avctx->streams[pkt->stream_index];
123 
125  return ndi_write_video_packet(avctx, st, pkt);
126  else if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)
127  return ndi_write_audio_packet(avctx, st, pkt);
128 
129  return AVERROR_BUG;
130 }
131 
132 static int ndi_setup_audio(AVFormatContext *avctx, AVStream *st)
133 {
134  struct NDIContext *ctx = avctx->priv_data;
136 
137  if (ctx->audio) {
138  av_log(avctx, AV_LOG_ERROR, "Only one audio stream is supported!\n");
139  return AVERROR(EINVAL);
140  }
141 
142  ctx->audio = av_mallocz(sizeof(NDIlib_audio_frame_interleaved_16s_t));
143  if (!ctx->audio)
144  return AVERROR(ENOMEM);
145 
146  ctx->audio->sample_rate = c->sample_rate;
147  ctx->audio->no_channels = c->channels;
148  ctx->audio->reference_level = ctx->reference_level;
149 
151 
152  return 0;
153 }
154 
155 static int ndi_setup_video(AVFormatContext *avctx, AVStream *st)
156 {
157  struct NDIContext *ctx = avctx->priv_data;
159 
160  if (ctx->video) {
161  av_log(avctx, AV_LOG_ERROR, "Only one video stream is supported!\n");
162  return AVERROR(EINVAL);
163  }
164 
166  av_log(avctx, AV_LOG_ERROR, "Unsupported codec format!"
167  " Only AV_CODEC_ID_WRAPPED_AVFRAME is supported (-vcodec wrapped_avframe).\n");
168  return AVERROR(EINVAL);
169  }
170 
171  if (c->format != AV_PIX_FMT_UYVY422 && c->format != AV_PIX_FMT_BGRA &&
172  c->format != AV_PIX_FMT_BGR0 && c->format != AV_PIX_FMT_RGBA &&
173  c->format != AV_PIX_FMT_RGB0) {
174  av_log(avctx, AV_LOG_ERROR, "Unsupported pixel format!"
175  " Only AV_PIX_FMT_UYVY422, AV_PIX_FMT_BGRA, AV_PIX_FMT_BGR0,"
176  " AV_PIX_FMT_RGBA, AV_PIX_FMT_RGB0 is supported.\n");
177  return AVERROR(EINVAL);
178  }
179 
180  if (c->field_order == AV_FIELD_BB || c->field_order == AV_FIELD_BT) {
181  av_log(avctx, AV_LOG_ERROR, "Lower field-first disallowed");
182  return AVERROR(EINVAL);
183  }
184 
185  ctx->video = av_mallocz(sizeof(NDIlib_video_frame_t));
186  if (!ctx->video)
187  return AVERROR(ENOMEM);
188 
189  switch(c->format) {
190  case AV_PIX_FMT_UYVY422:
191  ctx->video->FourCC = NDIlib_FourCC_type_UYVY;
192  break;
193  case AV_PIX_FMT_BGRA:
194  ctx->video->FourCC = NDIlib_FourCC_type_BGRA;
195  break;
196  case AV_PIX_FMT_BGR0:
197  ctx->video->FourCC = NDIlib_FourCC_type_BGRX;
198  break;
199  case AV_PIX_FMT_RGBA:
200  ctx->video->FourCC = NDIlib_FourCC_type_RGBA;
201  break;
202  case AV_PIX_FMT_RGB0:
203  ctx->video->FourCC = NDIlib_FourCC_type_RGBX;
204  break;
205  }
206 
207  ctx->video->xres = c->width;
208  ctx->video->yres = c->height;
209  ctx->video->frame_rate_N = st->avg_frame_rate.num;
210  ctx->video->frame_rate_D = st->avg_frame_rate.den;
211  ctx->video->frame_format_type = c->field_order == AV_FIELD_PROGRESSIVE
212  ? NDIlib_frame_format_type_progressive
213  : NDIlib_frame_format_type_interleaved;
214 
215  if (st->sample_aspect_ratio.num) {
216  AVRational display_aspect_ratio;
217  av_reduce(&display_aspect_ratio.num, &display_aspect_ratio.den,
218  st->codecpar->width * (int64_t)st->sample_aspect_ratio.num,
219  st->codecpar->height * (int64_t)st->sample_aspect_ratio.den,
220  1024 * 1024);
221  ctx->video->picture_aspect_ratio = av_q2d(display_aspect_ratio);
222  }
223  else
224  ctx->video->picture_aspect_ratio = (double)st->codecpar->width/st->codecpar->height;
225 
227 
228  return 0;
229 }
230 
232 {
233  int ret = 0;
234  unsigned int n;
235  struct NDIContext *ctx = avctx->priv_data;
236  const NDIlib_send_create_t ndi_send_desc = { .p_ndi_name = avctx->url,
237  .p_groups = NULL, .clock_video = ctx->clock_video, .clock_audio = ctx->clock_audio };
238 
239  if (!NDIlib_initialize()) {
240  av_log(avctx, AV_LOG_ERROR, "NDIlib_initialize failed.\n");
241  return AVERROR_EXTERNAL;
242  }
243 
244  /* check if streams compatible */
245  for (n = 0; n < avctx->nb_streams; n++) {
246  AVStream *st = avctx->streams[n];
248  if (c->codec_type == AVMEDIA_TYPE_AUDIO) {
249  if ((ret = ndi_setup_audio(avctx, st)))
250  goto error;
251  } else if (c->codec_type == AVMEDIA_TYPE_VIDEO) {
252  if ((ret = ndi_setup_video(avctx, st)))
253  goto error;
254  } else {
255  av_log(avctx, AV_LOG_ERROR, "Unsupported stream type.\n");
256  ret = AVERROR(EINVAL);
257  goto error;
258  }
259  }
260 
261  ctx->ndi_send = NDIlib_send_create(&ndi_send_desc);
262  if (!ctx->ndi_send) {
263  av_log(avctx, AV_LOG_ERROR, "Failed to create NDI output %s\n", avctx->url);
264  ret = AVERROR_EXTERNAL;
265  }
266 
267 error:
268  return ret;
269 }
270 
271 #define OFFSET(x) offsetof(struct NDIContext, x)
272 static const AVOption options[] = {
273  { "reference_level", "The audio reference level in dB" , OFFSET(reference_level), AV_OPT_TYPE_INT, { .i64 = 0 }, -20, 20, AV_OPT_FLAG_ENCODING_PARAM | AV_OPT_FLAG_AUDIO_PARAM},
274  { "clock_video", "These specify whether video 'clock' themselves" , OFFSET(clock_video), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, AV_OPT_FLAG_ENCODING_PARAM | AV_OPT_FLAG_VIDEO_PARAM },
275  { "clock_audio", "These specify whether audio 'clock' themselves" , OFFSET(clock_audio), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, AV_OPT_FLAG_ENCODING_PARAM | AV_OPT_FLAG_AUDIO_PARAM },
276  { NULL },
277 };
278 
280  .class_name = "NDI muxer",
281  .item_name = av_default_item_name,
282  .option = options,
283  .version = LIBAVUTIL_VERSION_INT,
285 };
286 
288  .name = "libndi_newtek",
289  .long_name = NULL_IF_CONFIG_SMALL("Network Device Interface (NDI) output using NewTek library"),
290  .audio_codec = AV_CODEC_ID_PCM_S16LE,
291  .video_codec = AV_CODEC_ID_WRAPPED_AVFRAME,
292  .subtitle_codec = AV_CODEC_ID_NONE,
293  .flags = AVFMT_NOFILE,
294  .priv_class = &libndi_newtek_muxer_class,
295  .priv_data_size = sizeof(struct NDIContext),
296  .write_header = ndi_write_header,
297  .write_packet = ndi_write_packet,
298  .write_trailer = ndi_write_trailer,
299 };
packed YUV 4:2:2, 16bpp, Cb Y0 Cr Y1
Definition: pixfmt.h:81
#define NULL
Definition: coverity.c:32
enum AVFieldOrder field_order
Video only.
Definition: avcodec.h:4025
This structure describes decoded (raw) audio or video data.
Definition: frame.h:268
AVOption.
Definition: opt.h:246
misc image utilities
#define LIBAVUTIL_VERSION_INT
Definition: version.h:85
void avpriv_set_pts_info(AVStream *s, int pts_wrap_bits, unsigned int pts_num, unsigned int pts_den)
Set the time base and wrapping info for a given stream.
Definition: utils.c:4882
enum AVCodecID codec_id
Specific type of the encoded data (the codec used).
Definition: avcodec.h:3944
AVRational sample_aspect_ratio
sample aspect ratio (0 if unknown)
Definition: avformat.h:936
int num
Numerator.
Definition: rational.h:59
#define AV_OPT_FLAG_AUDIO_PARAM
Definition: opt.h:278
int size
Definition: avcodec.h:1469
const char * av_default_item_name(void *ptr)
Return the context name.
Definition: log.c:191
static int ndi_write_header(AVFormatContext *avctx)
void * av_mallocz(size_t size)
Allocate a memory block with alignment suitable for all memory accesses (including vectors if availab...
Definition: mem.c:236
static AVPacket pkt
This struct describes the properties of an encoded stream.
Definition: avcodec.h:3936
Format I/O context.
Definition: avformat.h:1351
const char * class_name
The name of the class; usually it is the same name as the context structure type to which the AVClass...
Definition: log.h:72
int width
Video only.
Definition: avcodec.h:4010
packed RGB 8:8:8, 32bpp, RGBXRGBX... X=unused/undefined
Definition: pixfmt.h:238
AVOptions.
#define NDI_TIME_BASE_Q
Undefined Behavior In the C some operations are like signed integer dereferencing freed accessing outside allocated Undefined Behavior must not occur in a C it is not safe even if the output of undefined operations is unused The unsafety may seem nit picking but Optimizing compilers have in fact optimized code on the assumption that no undefined Behavior occurs Optimizing code based on wrong assumptions can and has in some cases lead to effects beyond the output of computations The signed integer overflow problem in speed critical code Code which is highly optimized and works with signed integers sometimes has the problem that often the output of the computation does not c
Definition: undefined.txt:32
AVFrame * last_avframe
AVStream ** streams
A list of all streams in the file.
Definition: avformat.h:1419
uint8_t * data
Definition: avcodec.h:1468
static double av_q2d(AVRational a)
Convert an AVRational to a double.
Definition: rational.h:104
static int ndi_write_packet(AVFormatContext *avctx, AVPacket *pkt)
int av_reduce(int *dst_num, int *dst_den, int64_t num, int64_t den, int64_t max)
Reduce a fraction.
Definition: rational.c:35
#define av_log(a,...)
#define AV_OPT_FLAG_ENCODING_PARAM
a generic parameter which can be set by the user for muxing or encoding
Definition: opt.h:276
static int ndi_write_trailer(AVFormatContext *avctx)
int64_t av_rescale_q(int64_t a, AVRational bq, AVRational cq)
Rescale a 64-bit integer by 2 rational numbers.
Definition: mathematics.c:142
int width
Definition: frame.h:326
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:176
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition: frame.c:202
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification. ...
Definition: internal.h:186
packed BGRA 8:8:8:8, 32bpp, BGRABGRA...
Definition: pixfmt.h:95
char * url
input or output URL.
Definition: avformat.h:1447
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition: log.h:197
enum AVMediaType codec_type
General type of the encoded data.
Definition: avcodec.h:3940
AVRational avg_frame_rate
Average framerate.
Definition: avformat.h:947
packed RGBA 8:8:8:8, 32bpp, RGBARGBA...
Definition: pixfmt.h:93
unsigned int nb_streams
Number of elements in AVFormatContext.streams.
Definition: avformat.h:1407
NDIlib_video_frame_t * video
static const AVOption options[]
const char * name
Definition: avformat.h:507
AVFormatContext * ctx
Definition: movenc.c:48
int n
Definition: avisynth_c.h:684
Passthrough codec, AVFrames wrapped in AVPacket.
Definition: avcodec.h:704
static void error(const char *err)
AVFrame * av_frame_clone(const AVFrame *src)
Create a new frame that references the same data as src.
Definition: frame.c:540
NDIlib_audio_frame_interleaved_16s_t * audio
if(ret)
Stream structure.
Definition: avformat.h:874
int format
format of the frame, -1 if unknown or unset Values correspond to enum AVPixelFormat for video frames...
Definition: frame.h:341
int linesize[AV_NUM_DATA_POINTERS]
For video, size in bytes of each picture line.
Definition: frame.h:299
#define AV_OPT_FLAG_VIDEO_PARAM
Definition: opt.h:279
#define AVERROR_BUG
Internal bug, also see AVERROR_BUG2.
Definition: error.h:50
Describe the class of an AVClass context structure.
Definition: log.h:67
Rational number (pair of numerator and denominator).
Definition: rational.h:58
packed BGR 8:8:8, 32bpp, BGRXBGRX... X=unused/undefined
Definition: pixfmt.h:240
static int ndi_setup_audio(AVFormatContext *avctx, AVStream *st)
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition: frame.h:282
int sample_rate
Audio only.
Definition: avcodec.h:4054
Main libavformat public API header.
#define AVFMT_NOFILE
Demuxer will use avio_open, no opened file should be provided by the caller.
Definition: avformat.h:465
int den
Denominator.
Definition: rational.h:60
static const AVClass libndi_newtek_muxer_class
const AVClass * cclass
void * priv_data
Format private data.
Definition: avformat.h:1379
int channels
Audio only.
Definition: avcodec.h:4050
static int ndi_write_audio_packet(AVFormatContext *avctx, AVStream *st, AVPacket *pkt)
static int ndi_write_video_packet(AVFormatContext *avctx, AVStream *st, AVPacket *pkt)
#define NDI_TIME_BASE
int height
Definition: frame.h:326
#define av_freep(p)
NDIlib_send_instance_t ndi_send
AVCodecParameters * codecpar
Codec parameters associated with this stream.
Definition: avformat.h:1021
int stream_index
Definition: avcodec.h:1470
AVRational time_base
This is the fundamental unit of time (in seconds) in terms of which frame timestamps are represented...
Definition: avformat.h:903
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later.That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another.Frame references ownership and permissions
AVOutputFormat ff_libndi_newtek_muxer
static int ndi_setup_video(AVFormatContext *avctx, AVStream *st)
#define OFFSET(x)
#define AVERROR_EXTERNAL
Generic error in an external library.
Definition: error.h:57
This structure stores compressed data.
Definition: avcodec.h:1445
int64_t pts
Presentation timestamp in AVStream->time_base units; the time at which the decompressed packet will b...
Definition: avcodec.h:1461
static uint8_t tmp[11]
Definition: aes_ctr.c:26