]> git.sesse.net Git - nageru/commitdiff
Initial checkin.
authorSteinar H. Gunderson <sgunderson@bigfoot.com>
Mon, 4 Jun 2018 20:48:16 +0000 (22:48 +0200)
committerSteinar H. Gunderson <sgunderson@bigfoot.com>
Mon, 4 Jun 2018 20:48:16 +0000 (22:48 +0200)
.gitignore [new file with mode: 0644]
Makefile [new file with mode: 0644]
ffmpeg_raii.cpp [new file with mode: 0644]
ffmpeg_raii.h [new file with mode: 0644]
frames/.empty [new file with mode: 0644]
main.cpp [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..e90caef
--- /dev/null
@@ -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 (file)
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 (file)
index 0000000..746e03d
--- /dev/null
@@ -0,0 +1,77 @@
+#include "ffmpeg_raii.h"
+
+extern "C" {
+#include <libavcodec/avcodec.h>
+#include <libavformat/avformat.h>
+#include <libavutil/dict.h>
+#include <libavutil/frame.h>
+#include <libswscale/swscale.h>
+}
+
+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 (file)
index 0000000..33d2334
--- /dev/null
@@ -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 <memory>
+
+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<AVFormatContext, avformat_close_input_unique>
+       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<AVCodecContext, avcodec_free_context_unique>
+       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<AVCodecParameters, avcodec_parameters_free_unique>
+       AVCodecParametersWithDeleter;
+
+
+// AVFrame
+struct av_frame_free_unique {
+       void operator() (AVFrame *frame) const;
+};
+
+typedef std::unique_ptr<AVFrame, av_frame_free_unique>
+       AVFrameWithDeleter;
+
+AVFrameWithDeleter av_frame_alloc_unique();
+
+// SwsContext
+struct sws_free_context_unique {
+       void operator() (SwsContext *context) const;
+};
+
+typedef std::unique_ptr<SwsContext, sws_free_context_unique>
+       SwsContextWithDeleter;
+
+#endif  // !defined(_FFMPEG_RAII_H)
diff --git a/frames/.empty b/frames/.empty
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/main.cpp b/main.cpp
new file mode 100644 (file)
index 0000000..810bcf3
--- /dev/null
+++ b/main.cpp
@@ -0,0 +1,47 @@
+#include <stdio.h>
+#include <memory>
+
+extern "C" {
+#include <libavformat/avformat.h>
+}
+
+#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<AVPacket, decltype(av_packet_unref)*> 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;
+}