--- /dev/null
+#ifndef SCF_DEF_H
+#define SCF_DEF_H
+
+#include<stdio.h>
+#include<stdint.h>
+#include<stdlib.h>
+#include<stddef.h>
+#include<string.h>
+#include<assert.h>
+#include<errno.h>
+#include<time.h>
+#include<unistd.h>
+#include<pthread.h>
+
+#if 1
+#include<sys/time.h>
+static inline int64_t gettime()
+{
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+
+ return tv.tv_sec * 1000000LL + tv.tv_usec;
+}
+#endif
+
+#ifdef SCF_DEBUG
+#define scf_logd(fmt, ...) printf("%s(), %d, "fmt, __func__, __LINE__, ##__VA_ARGS__)
+#else
+#define scf_logd(fmt, ...)
+#endif
+
+#define scf_logi(fmt, ...) printf("%s(), %d, info: "fmt, __func__, __LINE__, ##__VA_ARGS__)
+
+#define scf_loge(fmt, ...) printf("%s(), %d, \033[31m error:\033[0m "fmt, __func__, __LINE__, ##__VA_ARGS__)
+#define scf_logw(fmt, ...) printf("%s(), %d, \033[33m warning:\033[0m "fmt, __func__, __LINE__, ##__VA_ARGS__)
+
+#endif
+
--- /dev/null
+#ifndef SCF_LIST_H
+#define SCF_LIST_H
+
+#include"scf_def.h"
+
+typedef struct scf_list_s scf_list_t;
+
+struct scf_list_s {
+ struct scf_list_s* prev;
+ struct scf_list_s* next;
+};
+
+static inline void scf_list_init(scf_list_t* h)
+{
+ h->prev = h;
+ h->next = h;
+}
+
+static inline void scf_list_del(scf_list_t* n)
+{
+ n->prev->next = n->next;
+ n->next->prev = n->prev;
+
+ // only to avoid some wrong operations for these 2 invalid pointers
+ n->prev = NULL;
+ n->next = NULL;
+}
+
+static inline void scf_list_add_tail(scf_list_t* h, scf_list_t* n)
+{
+ h->prev->next = n;
+ n->prev = h->prev;
+ n->next = h;
+ h->prev = n;
+}
+
+static inline void scf_list_add_front(scf_list_t* h, scf_list_t* n)
+{
+ h->next->prev = n;
+ n->next = h->next;
+ n->prev = h;
+ h->next = n;
+}
+
+#define SCF_LIST_INIT(h) {&h, &h}
+
+#define scf_list_data(l, type, member) ((type*)((char*)l - offsetof(type, member)))
+
+#define scf_list_head(h) ((h)->next)
+#define scf_list_tail(h) ((h)->prev)
+#define scf_list_sentinel(h) (h)
+#define scf_list_next(l) ((l)->next)
+#define scf_list_prev(l) ((l)->prev)
+#define scf_list_empty(h) ((h)->next == (h))
+
+#define scf_list_clear(h, type, member, type_free) \
+ do {\
+ scf_list_t* l;\
+ for (l = scf_list_head(h); l != scf_list_sentinel(h);) {\
+ type* t = scf_list_data(l, type, member);\
+ l = scf_list_next(l);\
+ scf_list_del(&t->member);\
+ type_free(t);\
+ t = NULL;\
+ }\
+ } while(0)
+
+#define scf_list_mov(dst, src, type, member) \
+ do {\
+ scf_list_t* l;\
+ type* t;\
+ for (l = scf_list_head(src); l != scf_list_sentinel(src);) {\
+ t = scf_list_data(l, type, member);\
+ l = scf_list_next(l);\
+ scf_list_del(&t->member);\
+ scf_list_add_tail(dst, &t->member);\
+ }\
+ } while(0)
+
+#endif
+
--- /dev/null
+#ifndef SCF_VECTOR_H
+#define SCF_VECTOR_H
+
+#include"scf_def.h"
+
+typedef struct {
+ int capacity;
+ int size;
+ void** data;
+} scf_vector_t;
+
+#undef NB_MEMBER_INC
+#define NB_MEMBER_INC 16
+
+static inline scf_vector_t* scf_vector_alloc()
+{
+ scf_vector_t* v = calloc(1, sizeof(scf_vector_t));
+ if (!v)
+ return NULL;
+
+ v->data = calloc(NB_MEMBER_INC, sizeof(void*));
+ if (!v->data) {
+ free(v);
+ v = NULL;
+ return NULL;
+ }
+
+ v->capacity = NB_MEMBER_INC;
+ return v;
+}
+
+static inline scf_vector_t* scf_vector_clone(scf_vector_t* origin)
+{
+ scf_vector_t* clone = calloc(1, sizeof(scf_vector_t));
+ if (!clone)
+ return NULL;
+
+ clone->data = calloc(origin->capacity, sizeof(void*));
+ if (!clone->data) {
+ free(clone);
+ clone = NULL;
+ return NULL;
+ }
+
+ clone->capacity = origin->capacity;
+ clone->size = origin->size;
+ memcpy(clone->data, origin->data, origin->size * sizeof(void*));
+ return clone;
+}
+
+static inline int scf_vector_cat(scf_vector_t* dst, scf_vector_t* src)
+{
+ if (!dst || !src)
+ return -EINVAL;
+
+ int size = dst->size + src->size;
+ if (size > dst->capacity) {
+
+ void* p = realloc(dst->data, sizeof(void*) * (size + NB_MEMBER_INC));
+ if (!p)
+ return -ENOMEM;
+
+ dst->data = p;
+ dst->capacity = size + NB_MEMBER_INC;
+ }
+
+ memcpy(dst->data + dst->size * sizeof(void*), src->data, src->size * sizeof(void*));
+ dst->size += src->size;
+ return 0;
+}
+
+static inline int scf_vector_add(scf_vector_t* v, void* node)
+{
+ if (!v || !v->data)
+ return -EINVAL;
+
+ assert(v->size <= v->capacity);
+
+ if (v->size == v->capacity) {
+ void* p = realloc(v->data, sizeof(void*) * (v->capacity + NB_MEMBER_INC));
+ if (!p)
+ return -ENOMEM;
+
+ v->data = p;
+ v->capacity += NB_MEMBER_INC;
+ }
+
+ v->data[v->size++] = node;
+ return 0;
+}
+
+static inline int scf_vector_del(scf_vector_t* v, void* node)
+{
+ if (!v || !v->data)
+ return -EINVAL;
+
+ assert(v->size <= v->capacity);
+
+ int i;
+ for (i = 0; i < v->size; i++) {
+
+ if (v->data[i] != node)
+ continue;
+
+ int j;
+ for (j = i + 1; j < v->size; j++)
+ v->data[j - 1] = v->data[j];
+
+ v->size--;
+
+ if (v->size + NB_MEMBER_INC * 2 < v->capacity) {
+ void* p = realloc(v->data, sizeof(void*) * (v->capacity - NB_MEMBER_INC));
+ if (p) {
+ v->data = p;
+ v->capacity -= NB_MEMBER_INC;
+ }
+ }
+ return 0;
+ }
+
+ return -1;
+}
+
+static inline void* scf_vector_find(const scf_vector_t* v, const void* node)
+{
+ int i;
+ for (i = 0; i < v->size; i++) {
+ if (node == v->data[i])
+ return v->data[i];
+ }
+ return NULL;
+}
+
+static inline int scf_vector_add_unique(scf_vector_t* v, void* node)
+{
+ if (!scf_vector_find(v, node))
+ return scf_vector_add(v, node);
+ return 0;
+}
+
+static inline void* scf_vector_find_cmp(const scf_vector_t* v, const void* node, int (*cmp)(const void*, const void*))
+{
+ int i;
+ for (i = 0; i < v->size; i++) {
+ if (0 == cmp(node, v->data[i]))
+ return v->data[i];
+ }
+ return NULL;
+}
+
+static inline int scf_vector_qsort(const scf_vector_t* v, int (*cmp)(const void*, const void*))
+{
+ if (!v || !v->data || 0 == v->size || !cmp)
+ return -EINVAL;
+
+ qsort(v->data, v->size, sizeof(void*), cmp);
+ return 0;
+}
+
+static inline void scf_vector_clear(scf_vector_t* v, void (*type_free)(void*))
+{
+ if (!v || !v->data)
+ return;
+
+ if (type_free) {
+ int i;
+ for (i = 0; i < v->size; i++) {
+ if (v->data[i]) {
+ type_free(v->data[i]);
+ v->data[i] = NULL;
+ }
+ }
+ }
+
+ v->size = 0;
+
+ if (v->capacity > NB_MEMBER_INC) {
+ void* p = realloc(v->data, sizeof(void*) * NB_MEMBER_INC);
+ if (p) {
+ v->data = p;
+ v->capacity = NB_MEMBER_INC;
+ }
+ }
+}
+
+static inline void scf_vector_free(scf_vector_t* v)
+{
+ if (v) {
+ if (v->data)
+ free(v->data);
+
+ free(v);
+ v = NULL;
+ }
+}
+
+#endif
+
--- /dev/null
+#include"simp.h"
+
+static simp_avio_ops_t* avio_array[] =
+{
+ NULL,
+};
+
+simp_frame_t* simp_frame_alloc()
+{
+ simp_frame_t* f = malloc(sizeof(simp_frame_t));
+ if (!f)
+ return NULL;
+
+ f->frame = av_frame_alloc();
+ if (!f->frame) {
+ free(f);
+ return NULL;
+ }
+
+ return f;
+}
+
+void simp_frame_free (simp_frame_t* f)
+{
+ if (f) {
+ if (f->frame)
+ av_frame_free(&f->frame);
+
+ free(f);
+ }
+}
+
+int simp_avio_open(simp_avio_t** pio, const char* type, const char* path)
+{
+ if (!pio || !type || !path)
+ return -EINVAL;
+
+ simp_avio_ops_t* ops = NULL;
+ simp_avio_t* io = NULL;
+
+ int i;
+ for (i = 0; avio_array[i]; i++) {
+
+ if (!strcmp(avio_array[i]->type, type)) {
+ ops = avio_array[i];
+ break;
+ }
+ }
+
+ if (!ops)
+ return -EINVAL;
+
+ io = calloc(1, sizeof(simp_avio_t));
+ if (!io)
+ return -ENOMEM;
+
+ scf_list_init(&io->list);
+ scf_list_init(&io->vin);
+ scf_list_init(&io->ain);
+ scf_list_init(&io->vout);
+ scf_list_init(&io->aout);
+
+ io->width = -1;
+ io->height = -1;
+ io->channels = -1;
+
+ io->ops = ops;
+ if (ops->open) {
+
+ int ret = ops->open(io, path);
+ if (ret < 0) {
+ free(io);
+ return ret;
+ }
+ }
+
+ *pio = io;
+ return 0;
+}
+
+int simp_avio_close(simp_avio_t* io)
+{
+ if (io) {
+ if (io->ops && io->ops->close)
+ io->ops->close(io);
+
+ free(io);
+ }
+ return 0;
+}
+
+int simp_avio_run(simp_avio_t* io)
+{
+ if (io && io->ops && io->ops->run)
+ return io->ops->run(io);
+
+ return -EINVAL;
+}
+
+int simp_filter_open(simp_filter_t** pf)
+{
+
+}
+
+int simp_filter_close(simp_filter_t* f)
+{
+
+}
+
+int simp_filter_run(simp_filter_t* f)
+{
+
+}
+
+int simp_filter_add_input (simp_filter_t* f, simp_avio_t* input)
+{
+
+}
+
+int simp_filter_add_output(simp_filter_t* f, simp_avio_t* output)
+{
+
+}
+
--- /dev/null
+#ifndef SIMP_H
+#define SIMP_H
+
+#include"scf_list.h"
+
+#include "libavformat/avformat.h"
+#include "libavcodec/avcodec.h"
+#include "libavutil/avutil.h"
+#include "libavutil/opt.h"
+#include "libavfilter/avfilter.h"
+#include "libavfilter/buffersrc.h"
+#include "libavfilter/buffersink.h"
+
+typedef struct simp_avio_s simp_avio_t;
+typedef struct simp_avio_ops_s simp_avio_ops_t;
+
+typedef struct simp_frame_s simp_frame_t;
+
+typedef struct simp_filter_s simp_filter_t;
+
+
+struct simp_frame_s
+{
+ scf_list_t list;
+ AVFrame* frame;
+};
+
+struct simp_avio_s
+{
+ scf_list_t list;
+
+ scf_list_t vin;
+ scf_list_t ain;
+
+ scf_list_t vout;
+ scf_list_t aout;
+
+ int width;
+ int height;
+ enum AVPixelFormat pix_fmt;
+ AVRational frame_rate;
+
+ enum AVSampleFormat sample_fmt;
+ AVRational sample_rate;
+ int channels;
+
+ simp_avio_ops_t* ops;
+ void* priv;
+};
+
+struct simp_filter_s
+{
+ scf_list_t inputs;
+ scf_list_t outputs;
+
+ AVFilterGraph* graph;
+ AVFilterContext* abuffersrc;
+ AVFilterContext* abuffersink;
+ AVFilterContext* vbuffersrc;
+ AVFilterContext* vbuffersink;
+};
+
+struct simp_avio_ops_s
+{
+ const char* type;
+
+ int (*open )(simp_avio_t* io, const char* path);
+ int (*close)(simp_avio_t* io);
+ int (*run )(simp_avio_t* io);
+};
+
+simp_frame_t* simp_frame_alloc();
+void simp_frame_free (simp_frame_t* f);
+
+int simp_avio_open (simp_avio_t** pio, const char* type, const char* path);
+int simp_avio_close (simp_avio_t* io);
+int simp_avio_run (simp_avio_t* io);
+
+int simp_filter_open (simp_filter_t** pf);
+int simp_filter_close (simp_filter_t* f);
+int simp_filter_run (simp_filter_t* f);
+
+int simp_filter_add_input (simp_filter_t* f, simp_avio_t* input);
+int simp_filter_add_output(simp_filter_t* f, simp_avio_t* output);
+
+#endif
+
--- /dev/null
+#include"simp_ffmpeg.h"
+#include"scf_log.h"
+
+static int _video_init(simp_ffmpeg_t* priv)
+{
+ AVStream* s;
+ AVCodec* c;
+
+ s = priv->fmt_ctx->streams[priv->vidx];
+
+ c = avcodec_find_decoder(s->codecpar->codec_id);
+ if (!c) {
+ scf_loge("decoder not found, codec_id: %d\n", s->codecpar->codec_id);
+ return -1;
+ }
+
+ priv->vdec_ctx = avcodec_alloc_context3(c);
+ if (!priv->vdec_ctx)
+ return -1;
+
+ int ret = avcodec_parameters_to_context(priv->vdec_ctx, s->codecpar);
+ if (ret < 0)
+ return -1;
+
+ ret = avcodec_open2(priv->vdec_ctx, c, NULL);
+ if (ret < 0) {
+ printf("avcodec_parameters_to_context error, ret: %d, %s\n", ret, av_err2str(ret));
+ return -1;
+ }
+
+ return 0;
+}
+
+static int _audio_init(simp_ffmpeg_t* priv)
+{
+ AVStream* s;
+ AVCodec* c;
+
+ s = priv->fmt_ctx->streams[priv->aidx];
+
+ c = avcodec_find_decoder(s->codecpar->codec_id);
+ if (!c) {
+ scf_loge("decoder not found, codec_id: %d\n", s->codecpar->codec_id);
+ return -1;
+ }
+
+ priv->adec_ctx = avcodec_alloc_context3(c);
+ if (!priv->adec_ctx)
+ return -1;
+
+ int ret = avcodec_parameters_to_context(priv->adec_ctx, s->codecpar);
+ if (ret < 0)
+ return -1;
+
+ ret = avcodec_open2(priv->adec_ctx, c, NULL);
+ if (ret < 0) {
+ printf("avcodec_parameters_to_context error, ret: %d, %s\n", ret, av_err2str(ret));
+ return -1;
+ }
+
+ return 0;
+}
+
+static int _ffmpeg_open(simp_avio_t* io, const char* path)
+{
+ simp_ffmpeg_t* priv;
+ AVStream* s;
+
+ int ret;
+ int i;
+
+ priv = calloc(1, sizeof(simp_ffmpeg_t));
+ if (!priv)
+ return -ENOMEM;
+
+ pthread_mutex_init(&priv->mutex);
+ pthread_cond_init (&priv->cond);
+
+ priv->tid = -1;
+
+ priv->vidx = -1;
+ priv->aidx = -1;
+
+ ret = avformat_open_input(&priv->fmt_ctx, path, NULL, NULL);
+ if (ret < 0) {
+ scf_loge("ret: %s\n", av_err2str(ret));
+ goto error;
+ }
+
+ ret = avformat_find_stream_info(priv->fmt_ctx, NULL);
+ if (ret < 0) {
+ scf_loge("avformat_find_stream_info error, ret: %s\n", av_err2str(ret));
+ goto error;
+ }
+
+ for (i = 0; i < priv->fmt_ctx->nb_streams; i++) {
+ s = priv->fmt_ctx->streams[i];
+
+ if (AVMEDIA_TYPE_VIDEO == s->codecpar->codec_type)
+ priv->vidx = i;
+
+ else if (AVMEDIA_TYPE_AUDIO == s->codecpar->codec_type)
+ priv->aidx = i;
+
+ if (-1 != priv->vidx && -1 != priv->aidx)
+ break;
+ }
+
+ if (-1 == priv->vidx && -1 == priv->aidx) {
+ scf_loge("no stream found\n");
+
+ ret = -1;
+ goto error;
+ }
+
+ if (priv->vidx >= 0) {
+ ret = _video_init(priv);
+ if (ret < 0)
+ goto error;
+ }
+
+ if (priv->aidx >= 0) {
+ ret = _audio_init(priv);
+ if (ret < 0)
+ goto error;
+ }
+
+ io->priv = priv;
+ return 0;
+
+error:
+ if (priv->fmt_ctx)
+ avformat_close_input(&priv->fmt_ctx);
+
+ if (priv->vdec_ctx)
+ avcodec_close(priv->vdec_ctx);
+
+ if (priv->adec_ctx)
+ avcodec_close(priv->adec_ctx);
+
+ free(priv);
+ return ret;
+}
+
+static int _ffmpeg_close(simp_avio_t* io)
+{
+ simp_ffmpeg_t* priv;
+
+ if (io) {
+ priv = io->priv;
+
+ if (priv) {
+
+ if (priv->fmt_ctx)
+ avformat_close_input(&priv->fmt_ctx);
+
+ if (priv->vdec_ctx)
+ avcodec_close(priv->vdec_ctx);
+
+ if (priv->adec_ctx)
+ avcodec_close(priv->adec_ctx);
+
+ free(priv);
+ }
+ }
+
+ return 0;
+}
+
+void* __ffmpeg_run(void* arg)
+{
+ simp_avio_t* io = arg;
+ simp_ffmpeg_t* priv = io->priv;
+ AVPacket* pkt;
+
+ pkt = av_packet_alloc();
+ if (!pkt)
+ return NULL;
+
+ int key_frame = 0;
+
+ while (!priv->exit) {
+
+ int ret = av_read_frame(priv->fmt_ctx, pkt);
+ if (ret < 0) {
+ scf_loge("av_read_frame error, ret: %s\n", av_err2str(ret));
+ av_packet_free(&pkt);
+ break;
+ }
+
+ if (pkt->stream_index == priv->aidx) {
+
+ if (0 == key_frame) {
+ av_packet_unref(pkt);
+ continue;
+ }
+
+ } else if (pkt->stream_index == priv->vidx) {
+
+ if (pkt->flags & AV_PKT_FLAG_KEY)
+ key_frame++;
+
+ if (0 == key_frame) {
+ av_packet_unref(pkt);
+ continue;
+ }
+
+ ret = avcodec_send_packet(priv->vdec_ctx, pkt);
+ av_packet_unref(&pkt);
+ if (ret < 0) {
+ scf_loge("avcodec_send_packet error, ret: %s\n", av_err2str(ret));
+ break;
+ }
+
+ while (ret >= 0) {
+ ret = avcodec_receive_frame(priv->vdec_ctx, frame);
+ }
+
+ } else {
+ av_packet_unref(pkt);
+ continue;
+ }
+ }
+
+ return NULL;
+}
+
+static int _ffmpeg_run(simp_avio_t* io)
+{
+ simp_ffmpeg_t* priv = io->priv;
+
+ if (pthread_create(&priv->tid, NULL, __ffmpeg_run, io)) {
+ scf_loge("\n");
+ return -1;
+ }
+
+ return 0;
+}
+
--- /dev/null
+#ifndef SIMP_FFMPEG_H
+#define SIMP_FFMPEG_H
+
+#include"simp.h"
+
+typedef struct {
+ AVFormatContext* fmt_ctx;
+ AVCodecContext* vdec_ctx;
+ AVCodecContext* adec_ctx;
+
+ int vidx;
+ int aidx;
+
+ int exit;
+ pthread_t tid;
+ pthread_mutex_t mutex;
+ pthread_cond_t cond;
+
+} simp_ffmpeg_t;
+
+#endif
+