From: Luca Abeni Date: Wed, 5 Nov 2008 10:37:31 +0000 (+0100) Subject: First import... X-Git-Url: http://rtime.felk.cvut.cz/gitweb/frescor/streamer.git/commitdiff_plain/7d093c68e5e734896dd5b45f5f2021ed16f8a90f First import... --- 7d093c68e5e734896dd5b45f5f2021ed16f8a90f 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; +} +