From: Steinar H. Gunderson Date: Mon, 4 Jun 2018 20:48:16 +0000 (+0200) Subject: Initial checkin. X-Git-Tag: 1.8.0~76^2~292 X-Git-Url: https://git.sesse.net/?p=nageru;a=commitdiff_plain;h=b3e4f4b8458a052a7a8e252404f116a7b3c92864 Initial checkin. --- b3e4f4b8458a052a7a8e252404f116a7b3c92864 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e90caef --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +*.d +*.o +*.pb.h +*.pb.cc +*.moc.cpp +futatabi +frames/*.jpeg diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..05a6085 --- /dev/null +++ b/Makefile @@ -0,0 +1,37 @@ +CXX=g++ +PKG_MODULES := Qt5Core Qt5Gui Qt5Widgets Qt5PrintSupport libjpeg +CXXFLAGS ?= -O2 -g -Wall # Will be overridden by environment. +CXXFLAGS += -std=gnu++11 -fPIC $(shell pkg-config --cflags $(PKG_MODULES)) -pthread + +LDLIBS=$(shell pkg-config --libs $(PKG_MODULES)) -pthread -lavformat -lavcodec -lavutil -lswscale + +# Qt objects +OBJS_WITH_MOC = +OBJS += $(OBJS_WITH_MOC) +OBJS += $(OBJS_WITH_MOC:.o=.moc.o) + +OBJS += ffmpeg_raii.o main.o + +%.o: %.cpp + $(CXX) -MMD -MP $(CPPFLAGS) $(CXXFLAGS) -o $@ -c $< +%.o: %.cc + $(CXX) -MMD -MP $(CPPFLAGS) $(CXXFLAGS) -o $@ -c $< +%.pb.cc %.pb.h : %.proto + $(PROTOC) --cpp_out=. $< + +%.h: %.ui + uic $< -o $@ + +%.moc.cpp: %.h + moc $< -o $@ + +all: futatabi + +futatabi: $(OBJS) $(CEF_LIBS) + $(CXX) -o $@ $^ $(LDFLAGS) $(LDLIBS) + +DEPS=$(OBJS:.o=.d) +-include $(DEPS) + +clean: + $(RM) $(OBJS) $(DEPS) futatabi $(OBJS_WITH_MOC:.o=.moc.cpp) diff --git a/ffmpeg_raii.cpp b/ffmpeg_raii.cpp new file mode 100644 index 0000000..746e03d --- /dev/null +++ b/ffmpeg_raii.cpp @@ -0,0 +1,77 @@ +#include "ffmpeg_raii.h" + +extern "C" { +#include +#include +#include +#include +#include +} + +using namespace std; + +// AVFormatContext + +void avformat_close_input_unique::operator() (AVFormatContext *format_ctx) const +{ + avformat_close_input(&format_ctx); +} + +AVFormatContextWithCloser avformat_open_input_unique( + const char *pathname, AVInputFormat *fmt, + AVDictionary **options) +{ + return avformat_open_input_unique(pathname, fmt, options, AVIOInterruptCB{ nullptr, nullptr }); +} + +AVFormatContextWithCloser avformat_open_input_unique( + const char *pathname, AVInputFormat *fmt, + AVDictionary **options, + const AVIOInterruptCB &interrupt_cb) +{ + AVFormatContext *format_ctx = avformat_alloc_context(); + format_ctx->interrupt_callback = interrupt_cb; + if (avformat_open_input(&format_ctx, pathname, fmt, options) != 0) { + format_ctx = nullptr; + } + return AVFormatContextWithCloser(format_ctx); +} + +// AVCodecContext + +void avcodec_free_context_unique::operator() (AVCodecContext *codec_ctx) const +{ + avcodec_free_context(&codec_ctx); +} + +AVCodecContextWithDeleter avcodec_alloc_context3_unique(const AVCodec *codec) +{ + return AVCodecContextWithDeleter(avcodec_alloc_context3(codec)); +} + + +// AVCodecParameters + +void avcodec_parameters_free_unique::operator() (AVCodecParameters *codec_par) const +{ + avcodec_parameters_free(&codec_par); +} + +// AVFrame + +void av_frame_free_unique::operator() (AVFrame *frame) const +{ + av_frame_free(&frame); +} + +AVFrameWithDeleter av_frame_alloc_unique() +{ + return AVFrameWithDeleter(av_frame_alloc()); +} + +// SwsContext + +void sws_free_context_unique::operator() (SwsContext *context) const +{ + sws_freeContext(context); +} diff --git a/ffmpeg_raii.h b/ffmpeg_raii.h new file mode 100644 index 0000000..33d2334 --- /dev/null +++ b/ffmpeg_raii.h @@ -0,0 +1,80 @@ +#ifndef _FFMPEG_RAII_H +#define _FFMPEG_RAII_H 1 + +// Some helpers to make RAII versions of FFmpeg objects. +// The cleanup functions don't interact all that well with unique_ptr, +// so things get a bit messy and verbose, but overall it's worth it to ensure +// we never leak things by accident in error paths. +// +// This does not cover any of the types that can actually be declared as +// a unique_ptr with no helper functions for deleter. + +#include + +struct AVCodec; +struct AVCodecContext; +struct AVCodecParameters; +struct AVDictionary; +struct AVFormatContext; +struct AVFrame; +struct AVInputFormat; +struct SwsContext; +typedef struct AVIOInterruptCB AVIOInterruptCB; + +// AVFormatContext +struct avformat_close_input_unique { + void operator() (AVFormatContext *format_ctx) const; +}; + +typedef std::unique_ptr + AVFormatContextWithCloser; + +AVFormatContextWithCloser avformat_open_input_unique( + const char *pathname, AVInputFormat *fmt, + AVDictionary **options); + +AVFormatContextWithCloser avformat_open_input_unique( + const char *pathname, AVInputFormat *fmt, + AVDictionary **options, + const AVIOInterruptCB &interrupt_cb); + + +// AVCodecContext +struct avcodec_free_context_unique { + void operator() (AVCodecContext *ctx) const; +}; + +typedef std::unique_ptr + AVCodecContextWithDeleter; + +AVCodecContextWithDeleter avcodec_alloc_context3_unique(const AVCodec *codec); + + +// AVCodecParameters +struct avcodec_parameters_free_unique { + void operator() (AVCodecParameters *codec_par) const; +}; + +typedef std::unique_ptr + AVCodecParametersWithDeleter; + + +// AVFrame +struct av_frame_free_unique { + void operator() (AVFrame *frame) const; +}; + +typedef std::unique_ptr + AVFrameWithDeleter; + +AVFrameWithDeleter av_frame_alloc_unique(); + +// SwsContext +struct sws_free_context_unique { + void operator() (SwsContext *context) const; +}; + +typedef std::unique_ptr + SwsContextWithDeleter; + +#endif // !defined(_FFMPEG_RAII_H) diff --git a/frames/.empty b/frames/.empty new file mode 100644 index 0000000..e69de29 diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..810bcf3 --- /dev/null +++ b/main.cpp @@ -0,0 +1,47 @@ +#include +#include + +extern "C" { +#include +} + +#include "ffmpeg_raii.h" + +using namespace std; + +int main(void) +{ + av_register_all(); + avformat_network_init(); + + auto format_ctx = avformat_open_input_unique("example.mp4", nullptr, nullptr); + if (format_ctx == nullptr) { + fprintf(stderr, "%s: Error opening file\n", "example.mp4"); + return 1; + } + + for ( ;; ) { + AVPacket pkt; + unique_ptr pkt_cleanup( + &pkt, av_packet_unref); + av_init_packet(&pkt); + pkt.data = nullptr; + pkt.size = 0; + if (av_read_frame(format_ctx.get(), &pkt) != 0) { + break; + } + fprintf(stderr, "Got a frame from camera %d, pts = %ld, size = %d\n", + pkt.stream_index, pkt.pts, pkt.size); + char filename[256]; + snprintf(filename, sizeof(filename), "frames/cam%d-pts%09ld.jpeg", pkt.stream_index, pkt.pts); + FILE *fp = fopen(filename, "wb"); + if (fp == nullptr) { + perror(filename); + exit(1); + } + fwrite(pkt.data, pkt.size, 1, fp); + fclose(fp); + } + + return 0; +}