1cabdff1aSopenharmony_ci#include <stdio.h> 2cabdff1aSopenharmony_ci#include <stdlib.h> 3cabdff1aSopenharmony_ci#include <string.h> 4cabdff1aSopenharmony_ci#include "libavutil/avassert.h" 5cabdff1aSopenharmony_ci#include "libavdevice/avdevice.h" 6cabdff1aSopenharmony_ci#include "libavfilter/avfilter.h" 7cabdff1aSopenharmony_ci#include "libavfilter/buffersink.h" 8cabdff1aSopenharmony_ci#include "libavformat/avformat.h" 9cabdff1aSopenharmony_ci#include "libavcodec/codec_id.h" 10cabdff1aSopenharmony_ci 11cabdff1aSopenharmony_citypedef struct { 12cabdff1aSopenharmony_ci AVFormatContext *mux; 13cabdff1aSopenharmony_ci AVStream *stream; 14cabdff1aSopenharmony_ci AVFilterContext *sink; 15cabdff1aSopenharmony_ci} Stream; 16cabdff1aSopenharmony_ci 17cabdff1aSopenharmony_cistatic int create_sink(Stream *st, AVFilterGraph *graph, 18cabdff1aSopenharmony_ci AVFilterContext *f, int idx) 19cabdff1aSopenharmony_ci{ 20cabdff1aSopenharmony_ci enum AVMediaType type = avfilter_pad_get_type(f->output_pads, idx); 21cabdff1aSopenharmony_ci const char *sink_name; 22cabdff1aSopenharmony_ci int ret; 23cabdff1aSopenharmony_ci 24cabdff1aSopenharmony_ci switch (type) { 25cabdff1aSopenharmony_ci case AVMEDIA_TYPE_VIDEO: sink_name = "buffersink"; break; 26cabdff1aSopenharmony_ci case AVMEDIA_TYPE_AUDIO: sink_name = "abuffersink"; break; 27cabdff1aSopenharmony_ci default: 28cabdff1aSopenharmony_ci av_log(NULL, AV_LOG_ERROR, "Stream type not supported\n"); 29cabdff1aSopenharmony_ci return AVERROR(EINVAL); 30cabdff1aSopenharmony_ci } 31cabdff1aSopenharmony_ci ret = avfilter_graph_create_filter(&st->sink, 32cabdff1aSopenharmony_ci avfilter_get_by_name(sink_name), 33cabdff1aSopenharmony_ci NULL, NULL, NULL, graph); 34cabdff1aSopenharmony_ci if (ret < 0) 35cabdff1aSopenharmony_ci return ret; 36cabdff1aSopenharmony_ci ret = avfilter_link(f, idx, st->sink, 0); 37cabdff1aSopenharmony_ci if (ret < 0) 38cabdff1aSopenharmony_ci return ret; 39cabdff1aSopenharmony_ci return 0; 40cabdff1aSopenharmony_ci} 41cabdff1aSopenharmony_ci 42cabdff1aSopenharmony_ciint main(int argc, char **argv) 43cabdff1aSopenharmony_ci{ 44cabdff1aSopenharmony_ci char *in_graph_desc, **out_dev_name; 45cabdff1aSopenharmony_ci int nb_out_dev = 0, nb_streams = 0; 46cabdff1aSopenharmony_ci AVFilterGraph *in_graph = NULL; 47cabdff1aSopenharmony_ci Stream *streams = NULL, *st; 48cabdff1aSopenharmony_ci AVFrame *frame = NULL; 49cabdff1aSopenharmony_ci int i, j, run = 1, ret; 50cabdff1aSopenharmony_ci 51cabdff1aSopenharmony_ci //av_log_set_level(AV_LOG_DEBUG); 52cabdff1aSopenharmony_ci 53cabdff1aSopenharmony_ci if (argc < 3) { 54cabdff1aSopenharmony_ci av_log(NULL, AV_LOG_ERROR, 55cabdff1aSopenharmony_ci "Usage: %s filter_graph dev:out [dev2:out2...]\n\n" 56cabdff1aSopenharmony_ci "Examples:\n" 57cabdff1aSopenharmony_ci "%s movie=file.nut:s=v+a xv:- alsa:default\n" 58cabdff1aSopenharmony_ci "%s movie=file.nut:s=v+a uncodedframecrc:pipe:0\n", 59cabdff1aSopenharmony_ci argv[0], argv[0], argv[0]); 60cabdff1aSopenharmony_ci exit(1); 61cabdff1aSopenharmony_ci } 62cabdff1aSopenharmony_ci in_graph_desc = argv[1]; 63cabdff1aSopenharmony_ci out_dev_name = argv + 2; 64cabdff1aSopenharmony_ci nb_out_dev = argc - 2; 65cabdff1aSopenharmony_ci 66cabdff1aSopenharmony_ci avdevice_register_all(); 67cabdff1aSopenharmony_ci 68cabdff1aSopenharmony_ci /* Create input graph */ 69cabdff1aSopenharmony_ci if (!(in_graph = avfilter_graph_alloc())) { 70cabdff1aSopenharmony_ci ret = AVERROR(ENOMEM); 71cabdff1aSopenharmony_ci av_log(NULL, AV_LOG_ERROR, "Unable to alloc graph graph: %s\n", 72cabdff1aSopenharmony_ci av_err2str(ret)); 73cabdff1aSopenharmony_ci goto fail; 74cabdff1aSopenharmony_ci } 75cabdff1aSopenharmony_ci ret = avfilter_graph_parse_ptr(in_graph, in_graph_desc, NULL, NULL, NULL); 76cabdff1aSopenharmony_ci if (ret < 0) { 77cabdff1aSopenharmony_ci av_log(NULL, AV_LOG_ERROR, "Unable to parse graph: %s\n", 78cabdff1aSopenharmony_ci av_err2str(ret)); 79cabdff1aSopenharmony_ci goto fail; 80cabdff1aSopenharmony_ci } 81cabdff1aSopenharmony_ci nb_streams = 0; 82cabdff1aSopenharmony_ci for (i = 0; i < in_graph->nb_filters; i++) { 83cabdff1aSopenharmony_ci AVFilterContext *f = in_graph->filters[i]; 84cabdff1aSopenharmony_ci for (j = 0; j < f->nb_inputs; j++) { 85cabdff1aSopenharmony_ci if (!f->inputs[j]) { 86cabdff1aSopenharmony_ci av_log(NULL, AV_LOG_ERROR, "Graph has unconnected inputs\n"); 87cabdff1aSopenharmony_ci ret = AVERROR(EINVAL); 88cabdff1aSopenharmony_ci goto fail; 89cabdff1aSopenharmony_ci } 90cabdff1aSopenharmony_ci } 91cabdff1aSopenharmony_ci for (j = 0; j < f->nb_outputs; j++) 92cabdff1aSopenharmony_ci if (!f->outputs[j]) 93cabdff1aSopenharmony_ci nb_streams++; 94cabdff1aSopenharmony_ci } 95cabdff1aSopenharmony_ci if (!nb_streams) { 96cabdff1aSopenharmony_ci av_log(NULL, AV_LOG_ERROR, "Graph has no output stream\n"); 97cabdff1aSopenharmony_ci ret = AVERROR(EINVAL); 98cabdff1aSopenharmony_ci goto fail; 99cabdff1aSopenharmony_ci } 100cabdff1aSopenharmony_ci if (nb_out_dev != 1 && nb_out_dev != nb_streams) { 101cabdff1aSopenharmony_ci av_log(NULL, AV_LOG_ERROR, 102cabdff1aSopenharmony_ci "Graph has %d output streams, %d devices given\n", 103cabdff1aSopenharmony_ci nb_streams, nb_out_dev); 104cabdff1aSopenharmony_ci ret = AVERROR(EINVAL); 105cabdff1aSopenharmony_ci goto fail; 106cabdff1aSopenharmony_ci } 107cabdff1aSopenharmony_ci 108cabdff1aSopenharmony_ci if (!(streams = av_calloc(nb_streams, sizeof(*streams)))) { 109cabdff1aSopenharmony_ci ret = AVERROR(ENOMEM); 110cabdff1aSopenharmony_ci av_log(NULL, AV_LOG_ERROR, "Could not allocate streams\n"); 111cabdff1aSopenharmony_ci } 112cabdff1aSopenharmony_ci st = streams; 113cabdff1aSopenharmony_ci for (i = 0; i < in_graph->nb_filters; i++) { 114cabdff1aSopenharmony_ci AVFilterContext *f = in_graph->filters[i]; 115cabdff1aSopenharmony_ci for (j = 0; j < f->nb_outputs; j++) { 116cabdff1aSopenharmony_ci if (!f->outputs[j]) { 117cabdff1aSopenharmony_ci if ((ret = create_sink(st++, in_graph, f, j)) < 0) 118cabdff1aSopenharmony_ci goto fail; 119cabdff1aSopenharmony_ci } 120cabdff1aSopenharmony_ci } 121cabdff1aSopenharmony_ci } 122cabdff1aSopenharmony_ci av_assert0(st - streams == nb_streams); 123cabdff1aSopenharmony_ci if ((ret = avfilter_graph_config(in_graph, NULL)) < 0) { 124cabdff1aSopenharmony_ci av_log(NULL, AV_LOG_ERROR, "Failed to configure graph\n"); 125cabdff1aSopenharmony_ci goto fail; 126cabdff1aSopenharmony_ci } 127cabdff1aSopenharmony_ci 128cabdff1aSopenharmony_ci /* Create output devices */ 129cabdff1aSopenharmony_ci for (i = 0; i < nb_out_dev; i++) { 130cabdff1aSopenharmony_ci char *fmt = NULL, *dev = out_dev_name[i]; 131cabdff1aSopenharmony_ci st = &streams[i]; 132cabdff1aSopenharmony_ci if ((dev = strchr(dev, ':'))) { 133cabdff1aSopenharmony_ci *(dev++) = 0; 134cabdff1aSopenharmony_ci fmt = out_dev_name[i]; 135cabdff1aSopenharmony_ci } 136cabdff1aSopenharmony_ci ret = avformat_alloc_output_context2(&st->mux, NULL, fmt, dev); 137cabdff1aSopenharmony_ci if (ret < 0) { 138cabdff1aSopenharmony_ci av_log(NULL, AV_LOG_ERROR, "Failed to allocate output: %s\n", 139cabdff1aSopenharmony_ci av_err2str(ret)); 140cabdff1aSopenharmony_ci goto fail; 141cabdff1aSopenharmony_ci } 142cabdff1aSopenharmony_ci if (!(st->mux->oformat->flags & AVFMT_NOFILE)) { 143cabdff1aSopenharmony_ci ret = avio_open2(&st->mux->pb, st->mux->url, AVIO_FLAG_WRITE, 144cabdff1aSopenharmony_ci NULL, NULL); 145cabdff1aSopenharmony_ci if (ret < 0) { 146cabdff1aSopenharmony_ci av_log(st->mux, AV_LOG_ERROR, "Failed to init output: %s\n", 147cabdff1aSopenharmony_ci av_err2str(ret)); 148cabdff1aSopenharmony_ci goto fail; 149cabdff1aSopenharmony_ci } 150cabdff1aSopenharmony_ci } 151cabdff1aSopenharmony_ci } 152cabdff1aSopenharmony_ci for (; i < nb_streams; i++) 153cabdff1aSopenharmony_ci streams[i].mux = streams[0].mux; 154cabdff1aSopenharmony_ci 155cabdff1aSopenharmony_ci /* Create output device streams */ 156cabdff1aSopenharmony_ci for (i = 0; i < nb_streams; i++) { 157cabdff1aSopenharmony_ci st = &streams[i]; 158cabdff1aSopenharmony_ci if (!(st->stream = avformat_new_stream(st->mux, NULL))) { 159cabdff1aSopenharmony_ci ret = AVERROR(ENOMEM); 160cabdff1aSopenharmony_ci av_log(NULL, AV_LOG_ERROR, "Failed to create output stream\n"); 161cabdff1aSopenharmony_ci goto fail; 162cabdff1aSopenharmony_ci } 163cabdff1aSopenharmony_ci st->stream->codecpar->codec_type = av_buffersink_get_type(st->sink); 164cabdff1aSopenharmony_ci st->stream->time_base = av_buffersink_get_time_base(st->sink); 165cabdff1aSopenharmony_ci switch (av_buffersink_get_type(st->sink)) { 166cabdff1aSopenharmony_ci case AVMEDIA_TYPE_VIDEO: 167cabdff1aSopenharmony_ci st->stream->codecpar->codec_id = AV_CODEC_ID_RAWVIDEO; 168cabdff1aSopenharmony_ci st->stream->avg_frame_rate = 169cabdff1aSopenharmony_ci st->stream-> r_frame_rate = av_buffersink_get_frame_rate(st->sink); 170cabdff1aSopenharmony_ci st->stream->codecpar->width = av_buffersink_get_w(st->sink); 171cabdff1aSopenharmony_ci st->stream->codecpar->height = av_buffersink_get_h(st->sink); 172cabdff1aSopenharmony_ci st->stream->codecpar->sample_aspect_ratio = av_buffersink_get_sample_aspect_ratio(st->sink); 173cabdff1aSopenharmony_ci st->stream->codecpar->format = av_buffersink_get_format(st->sink); 174cabdff1aSopenharmony_ci break; 175cabdff1aSopenharmony_ci case AVMEDIA_TYPE_AUDIO: 176cabdff1aSopenharmony_ci ret = av_buffersink_get_ch_layout(st->sink, &st->stream->codecpar->ch_layout); 177cabdff1aSopenharmony_ci if (ret < 0) 178cabdff1aSopenharmony_ci goto fail; 179cabdff1aSopenharmony_ci st->stream->codecpar->sample_rate = av_buffersink_get_sample_rate(st->sink); 180cabdff1aSopenharmony_ci st->stream->codecpar->format = av_buffersink_get_format(st->sink); 181cabdff1aSopenharmony_ci st->stream->codecpar->codec_id = av_get_pcm_codec(st->stream->codecpar->format, -1); 182cabdff1aSopenharmony_ci break; 183cabdff1aSopenharmony_ci default: 184cabdff1aSopenharmony_ci av_assert0(!"reached"); 185cabdff1aSopenharmony_ci } 186cabdff1aSopenharmony_ci } 187cabdff1aSopenharmony_ci 188cabdff1aSopenharmony_ci /* Init output devices */ 189cabdff1aSopenharmony_ci for (i = 0; i < nb_out_dev; i++) { 190cabdff1aSopenharmony_ci st = &streams[i]; 191cabdff1aSopenharmony_ci if ((ret = avformat_write_header(st->mux, NULL)) < 0) { 192cabdff1aSopenharmony_ci av_log(st->mux, AV_LOG_ERROR, "Failed to init output: %s\n", 193cabdff1aSopenharmony_ci av_err2str(ret)); 194cabdff1aSopenharmony_ci goto fail; 195cabdff1aSopenharmony_ci } 196cabdff1aSopenharmony_ci } 197cabdff1aSopenharmony_ci 198cabdff1aSopenharmony_ci /* Check output devices */ 199cabdff1aSopenharmony_ci for (i = 0; i < nb_streams; i++) { 200cabdff1aSopenharmony_ci st = &streams[i]; 201cabdff1aSopenharmony_ci ret = av_write_uncoded_frame_query(st->mux, st->stream->index); 202cabdff1aSopenharmony_ci if (ret < 0) { 203cabdff1aSopenharmony_ci av_log(st->mux, AV_LOG_ERROR, 204cabdff1aSopenharmony_ci "Uncoded frames not supported on stream #%d: %s\n", 205cabdff1aSopenharmony_ci i, av_err2str(ret)); 206cabdff1aSopenharmony_ci goto fail; 207cabdff1aSopenharmony_ci } 208cabdff1aSopenharmony_ci } 209cabdff1aSopenharmony_ci 210cabdff1aSopenharmony_ci while (run) { 211cabdff1aSopenharmony_ci ret = avfilter_graph_request_oldest(in_graph); 212cabdff1aSopenharmony_ci if (ret < 0) { 213cabdff1aSopenharmony_ci if (ret == AVERROR_EOF) { 214cabdff1aSopenharmony_ci run = 0; 215cabdff1aSopenharmony_ci } else { 216cabdff1aSopenharmony_ci av_log(NULL, AV_LOG_ERROR, "Error filtering: %s\n", 217cabdff1aSopenharmony_ci av_err2str(ret)); 218cabdff1aSopenharmony_ci break; 219cabdff1aSopenharmony_ci } 220cabdff1aSopenharmony_ci } 221cabdff1aSopenharmony_ci for (i = 0; i < nb_streams; i++) { 222cabdff1aSopenharmony_ci st = &streams[i]; 223cabdff1aSopenharmony_ci while (1) { 224cabdff1aSopenharmony_ci if (!frame && !(frame = av_frame_alloc())) { 225cabdff1aSopenharmony_ci ret = AVERROR(ENOMEM); 226cabdff1aSopenharmony_ci av_log(NULL, AV_LOG_ERROR, "Could not allocate frame\n"); 227cabdff1aSopenharmony_ci goto fail; 228cabdff1aSopenharmony_ci } 229cabdff1aSopenharmony_ci ret = av_buffersink_get_frame_flags(st->sink, frame, 230cabdff1aSopenharmony_ci AV_BUFFERSINK_FLAG_NO_REQUEST); 231cabdff1aSopenharmony_ci if (ret < 0) { 232cabdff1aSopenharmony_ci if (ret != AVERROR(EAGAIN) && ret != AVERROR_EOF) 233cabdff1aSopenharmony_ci av_log(NULL, AV_LOG_WARNING, "Error in sink: %s\n", 234cabdff1aSopenharmony_ci av_err2str(ret)); 235cabdff1aSopenharmony_ci break; 236cabdff1aSopenharmony_ci } 237cabdff1aSopenharmony_ci if (frame->pts != AV_NOPTS_VALUE) 238cabdff1aSopenharmony_ci frame->pts = av_rescale_q(frame->pts, 239cabdff1aSopenharmony_ci av_buffersink_get_time_base(st->sink), 240cabdff1aSopenharmony_ci st->stream->time_base); 241cabdff1aSopenharmony_ci ret = av_interleaved_write_uncoded_frame(st->mux, 242cabdff1aSopenharmony_ci st->stream->index, 243cabdff1aSopenharmony_ci frame); 244cabdff1aSopenharmony_ci frame = NULL; 245cabdff1aSopenharmony_ci if (ret < 0) { 246cabdff1aSopenharmony_ci av_log(st->mux, AV_LOG_ERROR, 247cabdff1aSopenharmony_ci "Error writing frame: %s\n", av_err2str(ret)); 248cabdff1aSopenharmony_ci goto fail; 249cabdff1aSopenharmony_ci } 250cabdff1aSopenharmony_ci } 251cabdff1aSopenharmony_ci } 252cabdff1aSopenharmony_ci } 253cabdff1aSopenharmony_ci ret = 0; 254cabdff1aSopenharmony_ci 255cabdff1aSopenharmony_ci for (i = 0; i < nb_out_dev; i++) { 256cabdff1aSopenharmony_ci st = &streams[i]; 257cabdff1aSopenharmony_ci av_write_trailer(st->mux); 258cabdff1aSopenharmony_ci } 259cabdff1aSopenharmony_ci 260cabdff1aSopenharmony_cifail: 261cabdff1aSopenharmony_ci av_frame_free(&frame); 262cabdff1aSopenharmony_ci avfilter_graph_free(&in_graph); 263cabdff1aSopenharmony_ci if (streams) { 264cabdff1aSopenharmony_ci for (i = 0; i < nb_out_dev; i++) { 265cabdff1aSopenharmony_ci st = &streams[i]; 266cabdff1aSopenharmony_ci if (st->mux) { 267cabdff1aSopenharmony_ci if (st->mux->pb) 268cabdff1aSopenharmony_ci avio_closep(&st->mux->pb); 269cabdff1aSopenharmony_ci avformat_free_context(st->mux); 270cabdff1aSopenharmony_ci } 271cabdff1aSopenharmony_ci } 272cabdff1aSopenharmony_ci } 273cabdff1aSopenharmony_ci av_freep(&streams); 274cabdff1aSopenharmony_ci return ret < 0; 275cabdff1aSopenharmony_ci} 276