47#include <libavcodec/avcodec.h>
48#include <libavformat/avformat.h>
49#include <libavutil/channel_layout.h>
69#define DEFAULT_FILENAME "out.mp4"
70#define DEFAULT_PIXEL_FORMAT AV_PIX_FMT_YUV420P
71#define MOD_NAME "[File disp.] "
104static void *
worker(
void *arg);
112 *available_cards = calloc(*
count,
sizeof **available_cards);
113 snprintf((*available_cards)[0].
name,
sizeof(*available_cards)[0].
name,
123 pthread_mutex_destroy(&s->
lock);
124 pthread_cond_destroy(&s->
cv);
129 avcodec_free_context(&s->
video.
enc);
130 avcodec_free_context(&s->
audio.
enc);
131 if (!(s->
format_ctx->oformat->flags & AVFMT_NOFILE)) {
145 "file:[full]help")
"\n\n");
150 "\t" TBOLD(
"max_av_diff")
" - allowed A/V descync length "
151 "(in seconds; default %.3f)\n",
155 char codec_note[] =
TBOLD(
156 "NUT")
" files are written uncompressed. For other file "
158 "FFmpeg")
" container default "
159 "codecs are used.\n\nDefault output file "
167 char *end_ptr = NULL;
169 while ((
item = strtok_r(
fmt,
":", &end_ptr))) {
171 char *
val = strchr(
item,
'=') + 1;
191 if (!strcmp(
fmt,
"help") || !strcmp(
fmt,
"fullhelp")) {
199 char *fmt_c = strdup(
fmt);
211 "from file extension, using NUT.\n");
212 avformat_alloc_output_context2(&s->
format_ctx, NULL,
"nut",
220 if (!(s->
format_ctx->oformat->flags & AVFMT_NOFILE)) {
231 int ret = pthread_mutex_init(&s->
lock, NULL);
232 ret |= pthread_cond_init(&s->
cv, NULL);
248 av_frame_free(&avfrm);
251static enum AVPixelFormat
258 return AV_PIX_FMT_GBRP10LE;
261 return AV_PIX_FMT_GBRP12LE;
264 return AV_PIX_FMT_YUV422P10LE;
278 AVFrame *
frame = av_frame_alloc();
282 int ret = av_frame_get_buffer(
frame, 0);
286 av_frame_free(&
frame);
304 pthread_mutex_lock(&s->
lock);
307 pthread_mutex_unlock(&s->
lock);
308 pthread_cond_signal(&s->
cv);
318 pthread_mutex_unlock(&s->
lock);
319 pthread_cond_signal(&s->
cv);
325 const enum AVPixelFormat *haystick)
327 for (
int i = 0; i < nmembers; ++i) {
328 if (haystick[i] == needle) {
355 enum AVPixelFormat fmts[AV_PIX_FMT_NB];
368 assert(c_len <= *
len);
375 assert(*
len == (
int)
sizeof *
desc);
401#if FF_API_NEW_CHANNEL_LAYOUT
403 ctx->ch_layout = (AVChannelLayout) AV_CHANNEL_LAYOUT_MASK(
404 ch_count, (1 << ch_count) - 1);
407 av_channel_layout_default(&ctx->ch_layout, ch_count);
410 ctx->channel_layout = av_get_default_channel_layout(ch_count);
417#if FF_API_NEW_CHANNEL_LAYOUT
418 frm->ch_layout = (AVChannelLayout) AV_CHANNEL_LAYOUT_MASK(
419 ch_count, (1 << ch_count) - 1);
421 frm->channel_layout = av_get_default_channel_layout(ch_count);
427 enum AVSampleFormat
fmt)
429 AVFrame *av_frm = av_frame_alloc();
430 av_frm->format =
fmt;
432 av_frm->sample_rate =
desc.sample_rate;
433 av_frm->nb_samples = nb_samples;
435 if (nb_samples == 0) {
438 int ret = av_frame_get_buffer(av_frm, 0);
441 av_frame_free(&av_frm);
447static enum AVSampleFormat
450 enum AVSampleFormat
fmt = AV_SAMPLE_FMT_NONE;
452 if (*fmts == AV_SAMPLE_FMT_S16P || *fmts == AV_SAMPLE_FMT_S16) {
455 if (*fmts == AV_SAMPLE_FMT_FLTP) {
461 "Only S16, S16P and FLTP samples are currently "
462 "handled, please report!");
470 enum AVCodecID codec_id = s->
format_ctx->oformat->audio_codec;
472 switch (aud_desc.
bps) {
474 codec_id = AV_CODEC_ID_PCM_U8;
477 codec_id = AV_CODEC_ID_PCM_S16LE;
481 codec_id = AV_CODEC_ID_PCM_S32LE;
487 const AVCodec *
codec = avcodec_find_encoder(codec_id);
489 codec = avcodec_find_encoder(codec_id);
493 avcodec_get_name(codec_id));
503 s->
video.
enc->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
512 ret = avcodec_parameters_from_context(s->
audio.
st->codecpar,
516 "Could not copy audio stream parameters: %s\n",
521 av_frame_free(tmp_frame);
525 (*tmp_frame)->nb_samples = 0;
535 const enum AVCodecID codec_id =
536 s->
is_nut ? AV_CODEC_ID_RAWVIDEO
538 const AVCodec *
codec = avcodec_find_encoder(codec_id);
541 avcodec_get_name(codec_id));
550 s->
video.
enc->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
551 av_opt_set(s->
video.
enc->priv_data,
"preset",
"ultrafast", 0);
552 av_opt_set(s->
video.
enc->priv_data,
"deadline",
"realtime", 0);
553 av_opt_set(s->
video.
enc->priv_data,
"cpu-used",
"8", 0);
560 ret = avcodec_parameters_from_context(s->
video.
st->codecpar,
564 "Could not copy video stream parameters: %s\n",
580 const AVFrame *aud_frm, AVFrame **tmp_aud_frame)
582 if (!vid_frm || (s->
audio.
st != NULL && !aud_frm)) {
584 MOD_NAME "Waiting for all streams to init.\n");
594 *saved_vid_desc = vid_desc;
597 if (aud_frm != NULL) {
604 *saved_aud_desc = aud_desc;
609 int ret = avformat_write_header(s->
format_ctx, NULL);
612 "Error occurred when opening output file: %s\n",
623 AVFrame *
frame, AVPacket *pkt)
626 int ret = avcodec_send_frame(ost->
enc,
frame);
633 ret = avcodec_receive_packet(ost->
enc, pkt);
634 if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
642 av_packet_rescale_ts(pkt, ost->
enc->time_base,
644 pkt->stream_index = ost->
st->index;
645 ret = av_interleaved_write_frame(format_ctx, pkt);
656 const AVFrame *aud_frm)
658 if (vid_frm != NULL) {
680#if FF_API_NEW_CHANNEL_LAYOUT
681 const int ch_count = src->ch_layout.nb_channels;
684 av_get_channel_layout_nb_channels(src->channel_layout);
686 const int s_bps = av_get_bytes_per_sample(src->format);
687 const int d_bps = av_get_bytes_per_sample(dst->format);
689 if (av_sample_fmt_is_planar(dst->format)) {
691 for (
int i = 0; i <
ch_count; ++i) {
692 dst_data[i] = (
char *) dst->data[i] +
693 (ptrdiff_t) dst->nb_samples * d_bps;
695 if (dst->format == AV_SAMPLE_FMT_FLTP) {
698 (
char *) src->data[0] +
699 (ptrdiff_t) skip_in_samples * s_bps *
ch_count,
702 assert(s_bps == d_bps);
705 (
char *) src->data[0] +
706 (ptrdiff_t) skip_in_samples * s_bps *
ch_count,
711 assert(s_bps == d_bps);
712 memcpy(dst->data[0] +
713 (ptrdiff_t) dst->nb_samples * s_bps *
ch_count,
715 (ptrdiff_t) skip_in_samples * s_bps *
ch_count,
716 (
size_t) nb_samples * s_bps *
ch_count);
718 dst->nb_samples += nb_samples;
727 (aud_frm->nb_samples *
NS_IN_SEC / aud_frm->sample_rate);
736 const int frame_size = s->
audio.
enc->frame_size;
737 int consumed_samples = 0;
738 while (tmp_frm->nb_samples +
739 (aud_frm->nb_samples - consumed_samples) >=
741 const int needed_samples = frame_size - tmp_frm->nb_samples;
746 consumed_samples += needed_samples;
747 tmp_frm->nb_samples = 0;
751 aud_frm->nb_samples - consumed_samples);
758 const long long vid_frm_time_ns =
779 MOD_NAME "A-V desync %f sec, video frame %s...\n",
809 AVFrame *aud_frm = NULL;
810 AVFrame *tmp_aud_frm = NULL;
811 AVPacket *pkt = av_packet_alloc();
814 pthread_mutex_lock(&s->
lock);
817 pthread_cond_wait(&s->
cv, &s->
lock);
827 av_frame_free(&aud_frm);
832 pthread_mutex_unlock(&s->
lock);
836 &saved_aud_desc, aud_frm,
842 if (!
check_reconf(&saved_vid_desc, vid_frm, &saved_aud_desc,
845 "Let us know if desired.\n");
851 av_frame_free(&aud_frm);
860 av_frame_free(&aud_frm);
861 if (tmp_aud_frm != NULL && tmp_aud_frm->nb_samples > 0) {
864 av_frame_free(&tmp_aud_frm);
865 av_packet_free(&pkt);
867 pthread_mutex_unlock(&s->
lock);
881 if (av_frm == NULL) {
884 memcpy(av_frm->data[0],
frame->data,
frame->data_len);
885 pthread_mutex_lock(&s->
lock);
891 pthread_mutex_unlock(&s->
lock);
892 pthread_cond_signal(&s->
cv);
920 return &display_file_info;
struct video_frame * frame
const char unsigned int flags
int void(** deleter)(void *))
void vf_free(struct video_frame *buf)
Frees video_frame structure.
struct video_desc video_desc_from_frame(const struct video_frame *frame)
Returns struct video_desc from video frame.
struct video_frame * vf_alloc_desc(struct video_desc desc)
Allocates video frame accordig given desc.
struct video_frame * vf_alloc_desc_data(struct video_desc desc)
This file contains definition of some common audio types.
void audio_start(struct state_audio *s)
int color_printf(const char *format,...)
void log_msg(int level, const char *format,...)
#define LOG_LEVEL_INFO
normal reporting
#define LOG_LEVEL_ERROR
general errors
#define LOG_LEVEL_WARNING
less severe errors
#define VIDEO_DISPLAY_ABI_VERSION
#define DISPLAY_FLAG_AUDIO_ANY
@ DISPLAY_PROPERTY_CODECS
list of natively supported codecs - codec_t[]
@ DISPLAY_PROPERTY_AUDIO_FORMAT
enum AVSampleFormat audio_bps_to_av_sample_fmt(int bps, bool planar)
struct audio_desc audio_desc_from_av_frame(const AVFrame *frm)
void ug_set_av_logging()
Sets specified log level either given explicitly or from UG-wide log_level.
@ LIBRARY_CLASS_VIDEO_DISPLAY
#define REGISTER_MODULE_WITH_FUNC(name, func, lclass, abi)
#define IS_KEY_PREFIX(tok, key)
expands to true value if <k> from tok in format <k>=<v> is prefix of key
int get_framerate_d(double fps)
int get_cpu_core_count(void)
int get_framerate_n(double fps)
struct used to comunicate with audio capture/playback device
struct video_frame * vid_frm
struct output_stream video
struct output_stream audio
struct to_lavc_vid_conv * video_conv
char filename[MAX_PATH_SIZE]
struct video_desc video_desc
time_ns_t max_av_diff_ns
max A/V diff in ns
AVFormatContext * format_ctx
char * data
Raw tile data. Pointer must be at least 4B aligned.
unsigned int width
width of every tile (!)
unsigned int height
height of every tile (!)
void(* data_deleter)(struct video_frame *)
Struct video_frame represents a video frame and contains video description.
struct tile tiles[FLEXIBLE_ARRAY_MEMBER]
struct video_frame_callbacks callbacks
void to_lavc_vid_conv_destroy(struct to_lavc_vid_conv **s_p)
int get_available_pix_fmts(codec_t in_codec, struct to_lavc_req_prop req_prop, enum AVPixelFormat fmts[AV_PIX_FMT_NB])
struct AVFrame * to_lavc_vid_conv(struct to_lavc_vid_conv *s, char *in_data)
struct to_lavc_vid_conv * to_lavc_vid_conv_init(codec_t in_pixfmt, int width, int height, enum AVPixelFormat out_pixfmt, int thread_count)
#define TO_LAVC_REQ_PROP_INIT
static time_ns_t get_time_in_ns()
This file contains some common data types.
@ R10k
RGB 10-bit packed - RGBX, big-endian (2 bit padding)
@ VIDEO_CODEC_COUNT
count of known video codecs (including VIDEO_CODEC_NONE)
@ R12L
RGB 12-bit packed, little-endian.
@ v210
YCbCr 422 10-bit - xVY0U|xY2UY1|xUY3V|xY5VY4, little-endian (2 bit padding /'x'/),...
char * wrap_paragraph(char *text)
enum AVPixelFormat get_ug_to_av_pixfmt(codec_t ug_codec)
struct audio_desc audio_desc_from_frame(const struct audio_frame *frame)
bool audio_desc_eq(struct audio_desc a1, struct audio_desc a2)
void interleaved2noninterleaved_float(char **out_ch, const char *in, int in_bps, int in_len, int channel_count)
void interleaved2noninterleaved2(char **out_ch, const char *in, int bps, int in_len, int channel_count)
This is an umbrella header for video functions.
static bool display_file_reconfigure_audio(void *state, int quant_samples, int channels, int sample_rate)
static void delete_frame(struct video_frame *frame)
static void file_append_audio_frame(AVFrame *dst, const AVFrame *src, int skip_in_samples, int nb_samples)
append nb_samples to from src to dst, skipping skip_in_samples from input
static void write_audio_frame(struct state_file *s, AVFrame *aud_frm, AVFrame *tmp_frm, AVPacket *pkt)
static void display_file_done(void *state)
static void write_frame(AVFormatContext *format_ctx, struct output_stream *ost, AVFrame *frame, AVPacket *pkt)
static bool configure_audio(struct state_file *s, struct audio_desc aud_desc, AVFrame **tmp_frame)
static void aud_frm_set_ch_layout(AVFrame *frm, int ch_count)
#define DEFAULT_PIXEL_FORMAT
static const void * display_file_info_get()
static enum AVPixelFormat file_get_pix_fmt(bool is_nut, codec_t ug_codec)
static void write_video_frame(struct state_file *s, struct video_frame *vid_frm, AVPacket *pkt)
static bool avp_is_in_set(enum AVPixelFormat needle, int nmembers, const enum AVPixelFormat *haystick)
static void * worker(void *arg)
static bool check_reconf(struct video_desc *saved_vid_desc, const struct video_frame *vid_frm, struct audio_desc *saved_aud_desc, const AVFrame *aud_frm)
static void display_file_probe(struct device_info **available_cards, int *count, void(**deleter)(void *))
static bool display_file_reconfigure(void *state, struct video_desc desc)
static struct video_frame * display_file_getf(void *state)
static void * display_file_init(struct module *parent, const char *fmt, unsigned int flags)
static enum AVSampleFormat select_sample_format(const enum AVSampleFormat *fmts)
static bool display_file_putf(void *state, struct video_frame *frame, long long timeout_ns)
static bool parse_fmt(struct state_file *s, char *fmt)
static void aud_ctx_set_ch_layout(struct AVCodecContext *ctx, int ch_count, bool raw)
static bool configure_video(struct state_file *s, struct video_desc vid_desc)
static void display_file_put_audio_frame(void *state, const struct audio_frame *frame)
static bool initialize(struct state_file *s, struct video_desc *saved_vid_desc, const struct video_frame *vid_frm, struct audio_desc *saved_aud_desc, const AVFrame *aud_frm, AVFrame **tmp_aud_frame)
static bool display_file_get_property(void *state, int property, void *val, size_t *len)
static AVFrame * alloc_audio_frame(struct audio_desc desc, int nb_samples, enum AVSampleFormat fmt)
bool video_desc_eq(struct video_desc a, struct video_desc b)
Compares two video descriptions.