From 7d093c68e5e734896dd5b45f5f2021ed16f8a90f Mon Sep 17 00:00:00 2001 From: Luca Abeni Date: Wed, 5 Nov 2008 11:37:31 +0100 Subject: [PATCH] First import... --- Makefile | 29 ++++++++++++ codec.c | 135 +++++++++++++++++++++++++++++++++++++++++++++++++++++ codec.h | 5 ++ input.c | 93 ++++++++++++++++++++++++++++++++++++ input.h | 3 ++ output.c | 63 +++++++++++++++++++++++++ output.h | 3 ++ rt.c | 19 ++++++++ rt.h | 2 + streamer.c | 76 ++++++++++++++++++++++++++++++ 10 files changed, 428 insertions(+) create mode 100644 Makefile create mode 100644 codec.c create mode 100644 codec.h create mode 100644 input.c create mode 100644 input.h create mode 100644 output.c create mode 100644 output.h create mode 100644 rt.c create mode 100644 rt.h create mode 100644 streamer.c diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..a5ab469 --- /dev/null +++ b/Makefile @@ -0,0 +1,29 @@ +FFSRC ?= $(FFDIR) +CPPFLAGS= -I $(FFSRC) +CFLAGS = -Wall +CFLAGS += -Wdeclaration-after-statement +CFLAGS += -Wno-switch -Wdisabled-optimization -Wpointer-arith -Wredundant-decls +CFLAGS += -Wno-pointer-sign +LDFLAGS= -L $(FFDIR)/libavutil -L $(FFDIR)/libavcodec -L $(FFDIR)/libavformat -L $(FFDIR)/libavdevice +LDLIBS = -lavdevice -lavformat -lavcodec -lavutil + +LDLIBS += -lm -lz +CFLAGS += -g + +OBJS = input.o codec.o output.o rt.o + +all: streamer + +streamer: streamer.o $(OBJS) + +clean: + rm -f *.o streamer *.d + +################################### +%.d: %.c + $(CC) $(CPPFLAGS) -MM -MF $@ $< + +%.o: %.d + +-include $(OBJS:.o=.d) + diff --git a/codec.c b/codec.c new file mode 100644 index 0000000..819343a --- /dev/null +++ b/codec.c @@ -0,0 +1,135 @@ +#include "libavformat/avformat.h" +#include "libavcodec/avcodec.h" +#include "libswscale/swscale.h" + +struct resample_data { + struct SwsContext *resample_ctx; + int in_height; + AVFrame resampled_frame; +}; + +int codec_open(AVFormatContext *ctx) +{ + AVCodec *codec; + int i, res; + + for (i = 0; i < ctx->nb_streams; i++) { + codec = avcodec_find_decoder(ctx->streams[i]->codec->codec_id); + if (!codec) { + fprintf(stderr, "Cannot find codec %d for input stream %d\n", + ctx->streams[i]->codec->codec_id, i); + return -1; + } + res = avcodec_open(ctx->streams[i]->codec, codec); + if (res < 0) { + fprintf(stderr, "Cannot open codec for input stream %d\n", i); + + return -1; + } + } + + return 0; +} + +int out_codec_open(AVFormatContext *ctx) +{ + AVCodec *codec; + int i, res; + + for (i = 0; i < ctx->nb_streams; i++) { + codec = avcodec_find_encoder(ctx->streams[i]->codec->codec_id); + if (!codec) { + fprintf(stderr, "Cannot find codec %d for output stream %d\n", + ctx->streams[i]->codec->codec_id, i); + return -1; + } + res = avcodec_open(ctx->streams[i]->codec, codec); + if (res < 0) { + fprintf(stderr, "Cannot open codec for input stream %d\n", i); + + return -1; + } + } + + return 0; +} + + +AVFrame *pkt_decode(AVFormatContext *ctx, AVPacket *pkt) +{ + static AVFrame frame; + int res, got; + + avcodec_get_frame_defaults(&frame); + res = avcodec_decode_video(ctx->streams[pkt->stream_index]->codec, + &frame, &got, pkt->data, pkt->size); + if (res < 0) { + got = res; + } + + if (got > 0) { + AVFrame *res; + struct resample_data *r; + + r = ctx->streams[pkt->stream_index]->codec->opaque; + if (r) { + sws_scale(r->resample_ctx, frame.data, frame.linesize, 0, + ctx->streams[pkt->stream_index]->codec->height, + r->resampled_frame.data, r->resampled_frame.linesize); + res = &r->resampled_frame; + } else { + res = &frame; + } + + return res; + } + + return NULL; +} + +int codec_connect(AVCodecContext *ic, AVCodecContext *oc) +{ + struct resample_data *r; + + if ((ic->width == oc->width) && (ic->height == oc->height) && (ic->pix_fmt == oc->pix_fmt)) { + return 0; + } + + r = av_malloc(sizeof(struct resample_data)); + r->resample_ctx = sws_getContext(ic->width, ic->height, ic->pix_fmt, + oc->width, oc->height, oc->pix_fmt, + SWS_BICUBIC, NULL, NULL, NULL); + if (r->resample_ctx == NULL) { + av_free(r); + + return -1; + } + avcodec_get_frame_defaults(&r->resampled_frame); + avpicture_alloc((AVPicture*)&r->resampled_frame, + oc->pix_fmt, oc->width, oc->height); + ic->opaque = r; + + return 1; +} + +AVPacket *pkt_encode(AVFormatContext *ctx, AVFrame *frame) +{ + AVCodecContext *c = ctx->streams[0]->codec; + static AVPacket pkt; + int res; + + if (pkt.data == NULL) { + pkt.size = 256 * 1024; + pkt.data = av_malloc(pkt.size); + } + res = avcodec_encode_video(c, pkt.data, pkt.size, frame); + if (c->coded_frame->pts != AV_NOPTS_VALUE) { + pkt.pts = av_rescale_q(c->coded_frame->pts, c->time_base, ctx->streams[0]->time_base); + } + if (res < 0) { + return NULL; + } + + return &pkt; +} + diff --git a/codec.h b/codec.h new file mode 100644 index 0000000..13764da --- /dev/null +++ b/codec.h @@ -0,0 +1,5 @@ +int codec_open(AVFormatContext *ctx); +int out_codec_open(AVFormatContext *ctx); +int codec_connect(AVCodecContext *ic, AVCodecContext *oc); +AVFrame *pkt_decode(AVFormatContext *ctx, AVPacket *pkt); +AVPacket *pkt_encode(AVFormatContext *ctx, AVFrame *frame); diff --git a/input.c b/input.c new file mode 100644 index 0000000..02a8b20 --- /dev/null +++ b/input.c @@ -0,0 +1,93 @@ +#include +#include "libavformat/avformat.h" +#include "input.h" + +static uint64_t time_convert(uint64_t time, AVStream *st) +{ + if (st->start_time != AV_NOPTS_VALUE) { +#if 1 + time -= st->start_time; +#else +fprintf(stderr, "%Ld\t%Ld\n", st->start_time, av_rescale_q(st->start_time, + st->time_base, AV_TIME_BASE_Q)); +#endif + } + time = av_rescale_q(time, st->time_base, AV_TIME_BASE_Q); + + return time; +} + +static void time_base_convert(AVPacket *pkt, AVStream *st) +{ + if (pkt->pts != AV_NOPTS_VALUE) { + pkt->pts = time_convert(pkt->pts, st); + } + if (pkt->dts != AV_NOPTS_VALUE) { + pkt->dts = time_convert(pkt->dts, st); + } + if (pkt->duration != 0) { + pkt->duration = av_rescale_q(pkt->duration, st->time_base, AV_TIME_BASE_Q); + } +} + +AVFormatContext *open_input_stream(const char *fname) +{ + AVFormatContext *s; + AVInputFormat *fmt; + AVFormatParameters param; + int res; + + memset(¶m, 0, sizeof(AVFormatParameters)); + /* FIXME: Set these!!! */ + param.width = 352; + param.height = 288; + param.pix_fmt = PIX_FMT_YUV420P; + param.time_base.den = 25; + param.time_base.num = 1; + fmt = av_find_input_format("video4linux2"); + res = av_open_input_file(&s, fname, fmt, 0, ¶m); + if (res < 0) { + fprintf(stderr, "Error opening %s: %d\n", fname, res); + + return NULL; + } + + res = av_find_stream_info(s); + if (res < 0) { + fprintf(stderr, "Cannot find codec parameters for %s\n", fname); + + return NULL; + } + + dump_format(s, 0, fname, 0); + + return s; +} + +void close_input_stream(AVFormatContext *s) +{ + av_close_input_file(s); +} + +AVPacket *read_input_packet(AVFormatContext *s) +{ + static AVPacket pkt; + AVStream *st; + int res; + + res = av_read_frame(s, &pkt); + if (res < 0) { + return NULL; + } + + st = s->streams[pkt.stream_index]; + if (pkt.dts == AV_NOPTS_VALUE) { + fprintf(stderr, "WTF??? Unknown DTS???\n"); + + return NULL; + } + + time_base_convert(&pkt, st); + + return &pkt; +} diff --git a/input.h b/input.h new file mode 100644 index 0000000..7fa7b9c --- /dev/null +++ b/input.h @@ -0,0 +1,3 @@ +AVFormatContext *open_input_stream(const char *fname); +void close_input_stream(AVFormatContext *s); +AVPacket *read_input_packet(AVFormatContext *s); diff --git a/output.c b/output.c new file mode 100644 index 0000000..939be99 --- /dev/null +++ b/output.c @@ -0,0 +1,63 @@ +#include "libavformat/avformat.h" + + +AVFormatContext *open_output_stream(const char *dst, int port, enum CodecType codec_type) +{ + AVFormatContext *s; + static AVOutputFormat *rtp_format; + AVStream *st; + + s = av_alloc_format_context(); + rtp_format = guess_format("rtp", NULL, NULL); + if (!rtp_format) { + fprintf(stderr, "Unable for find the RTP format for output\n"); + + return NULL; + } + + s->oformat = rtp_format; + st = av_new_stream(s, 0); + if (!st) { + fprintf(stderr, "Cannot allocate stream\n"); + + return NULL; + } + + snprintf(s->filename, sizeof(s->filename), "rtp://%s:%d", dst, port); + + /* open the UDP sockets for RTP and RTCP */ + if (url_fopen(&s->pb, s->filename, URL_WRONLY) < 0) { + fprintf(stderr, "Cannot open '%s'\n", s->filename); + /* FIXME: Free the stream! */ + + return NULL; + } + avcodec_get_context_defaults2(s->streams[0]->codec, codec_type); + s->streams[0]->codec->codec_id = av_guess_codec(s->oformat, NULL, s->filename, NULL, codec_type); + s->streams[0]->codec->codec_id = CODEC_ID_MPEG4; + s->streams[0]->codec->pix_fmt = PIX_FMT_YUV420P; + + return s; +} + +int pkt_send(AVFormatContext *ctx, AVPacket *pkt) +{ + static int inited; /* FIXME: HACK! */ + + + if (!inited) { + int res; + +fprintf(stderr,"initing!\n"); + res = av_write_header(ctx); + if (res < 0) { + fprintf(stderr, "Cannot open the out RTP stream!\n"); + + return res; + } + inited = 1; + } + + return av_write_frame(ctx, pkt); +} + diff --git a/output.h b/output.h new file mode 100644 index 0000000..98a2a2e --- /dev/null +++ b/output.h @@ -0,0 +1,3 @@ +int pkt_send(AVFormatContext *ctx, AVPacket *pkt); +AVFormatContext *open_output_stream(const char *dst, int port, enum CodecType codec_type); + diff --git a/rt.c b/rt.c new file mode 100644 index 0000000..34f859f --- /dev/null +++ b/rt.c @@ -0,0 +1,19 @@ +/* FIXME: Dummy implementations!!! */ +#include +#include + +static uint64_t start_time, start_time1; + +void rt_job_start(uint64_t t) +{ + start_time = t; + start_time1 = av_gettime(); +} + +void rt_job_end(void) +{ + uint64_t t; + + t = av_gettime(); + printf("%Lu %Lu %Lu\t%Lu %Lu\n", start_time, start_time1, t, t - start_time, t - start_time1); +} diff --git a/rt.h b/rt.h new file mode 100644 index 0000000..28e7303 --- /dev/null +++ b/rt.h @@ -0,0 +1,2 @@ +void rt_job_start(uint64_t t); +void rt_job_end(void); diff --git a/streamer.c b/streamer.c new file mode 100644 index 0000000..2774a7a --- /dev/null +++ b/streamer.c @@ -0,0 +1,76 @@ +#include "libavformat/avformat.h" +#include "libavdevice/avdevice.h" + +#include "input.h" +#include "output.h" +#include "codec.h" +#include "rt.h" + +static void sdp_print(AVFormatContext *s) +{ + char sdp[2048]; + FILE *f; + + f = fopen("sdp.txt", "w"); + avf_sdp_create(&s, 1, sdp, sizeof(sdp)); + fprintf(f, "%s\n", sdp); + fclose(f); +} + + +int main(int argc, char *argv[]) +{ + AVFormatContext *s, *os; + int done; + + avcodec_register_all(); + av_register_all(); + avdevice_register_all(); + + s = open_input_stream(argv[1]); + if (s == NULL) { + fprintf(stderr, "Cannot open input file %s\n", argv[1]); + + return -1; + } + codec_open(s); + os = open_output_stream("224.10.20.30", 20000, CODEC_TYPE_VIDEO); + if (os == NULL) { + fprintf(stderr, "Cannot open output stream\n"); + + return -1; + } + os->streams[0]->codec->width = s->streams[0]->codec->width; + os->streams[0]->codec->height = s->streams[0]->codec->height; + os->streams[0]->codec->time_base = s->streams[0]->codec->time_base; + codec_connect(s->streams[0]->codec, os->streams[0]->codec); + out_codec_open(os); + dump_format(os, 0, os->filename, 1); + sdp_print(os); + done = 0; + while (!done) { + AVPacket *pkt; + pkt = read_input_packet(s); + if (pkt == NULL) { + done = 1; + } else { + AVFrame *f; + AVPacket *opkt; + + pkt->pts += s->streams[pkt->stream_index]->start_time; + rt_job_start(pkt->pts); + f = pkt_decode(s, pkt); + if (f) { + opkt = pkt_encode(os, f); + if (opkt) { + pkt_send(os, opkt); + } + } + rt_job_end(); + av_free_packet(pkt); + } + } + + return 0; +} + -- 2.39.2