00001
00002
00003
00004
00005
00006 #include "config.h"
00007 #include "libavformat/internal.h"
00008 #include "libavutil/log.h"
00009 #include "libavutil/opt.h"
00010 #include "libavutil/parseutils.h"
00011 #include "libavutil/time.h"
00012 #include "libavutil/pixdesc.h"
00013 #include <time.h>
00014 #include "avdevice.h"
00015 #include <dlfcn.h>
00016 #include <unistd.h>
00017 #include <stdbool.h>
00018
00019 struct ASC {
00020 void* priv_data;
00021 void* data;
00022 int size;
00023 int width;
00024 int height;
00025 char pixfmtName[32];
00026 };
00027
00031 struct androidgrab {
00032 const AVClass *class;
00034 double framerate;
00035
00036 void* dlhandle;
00037 void (*asc_capture)(struct ASC*);
00038 struct ASC asc;
00039
00040 int interval;
00041 int64_t last_time;
00042
00043 bool should_reuse_data;
00044 };
00045
00056 static int
00057 androidgrab_read_header(AVFormatContext *s1)
00058 {
00059 struct androidgrab *agrab = s1->priv_data;
00060 AVStream *st = NULL;
00061
00062 st = avformat_new_stream(s1, NULL);
00063 if (!st) return AVERROR(ENOMEM);
00064
00065 avpriv_set_pts_info(st, 64, 1, 1000000);
00066
00067 agrab->interval = ((double)1000000)/agrab->framerate;
00068 agrab->dlhandle = dlopen(s1->filename, RTLD_NOW);
00069 if (!agrab->dlhandle) {
00070 av_log(s1, AV_LOG_ERROR, "dlopen err:%d(%s) %s\n", errno, strerror(errno), dlerror());
00071 return AVERROR(errno);
00072 }
00073
00074 agrab->asc_capture = dlsym(agrab->dlhandle, "asc_capture");
00075 if (!agrab->asc_capture) {
00076 av_log(s1, AV_LOG_ERROR, "dlsym err:%d(%s)\n", errno, strerror(errno));
00077 return AVERROR(errno);
00078 }
00079
00080 agrab->asc.priv_data = NULL;
00081 agrab->asc_capture(&agrab->asc);
00082 agrab->last_time = av_gettime();
00083
00084 agrab->should_reuse_data = true;
00085
00086 st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
00087 st->codec->codec_id = AV_CODEC_ID_RAWVIDEO;
00088 st->codec->width = agrab->asc.width;
00089 st->codec->height = agrab->asc.height;
00090 st->codec->pix_fmt = av_get_pix_fmt(agrab->asc.pixfmtName);
00091 st->codec->time_base = av_d2q(1/agrab->framerate, 1000000);
00092 st->codec->bit_rate = agrab->asc.size * agrab->framerate * 8;
00093
00094 return 0;
00095 }
00096
00104 static int
00105 androidgrab_read_packet(AVFormatContext *s1, AVPacket *pkt)
00106 {
00107
00108
00109
00110
00111 struct androidgrab *agrab = s1->priv_data;
00112 int64_t waitInterval;
00113
00114 av_init_packet(pkt);
00115
00116 if (agrab->should_reuse_data) {
00117 agrab->should_reuse_data = false;
00118 } else {
00119
00120 waitInterval = av_gettime() - (agrab->last_time + agrab->interval);
00121 if (waitInterval > 0)
00122 usleep(waitInterval);
00123
00124 agrab->asc_capture(&agrab->asc);
00125 agrab->last_time = av_gettime();
00126 }
00127
00128 pkt->data = agrab->asc.data;
00129 pkt->size = agrab->asc.size;
00130 pkt->pts = agrab->last_time;
00131
00132
00133
00134
00135 return agrab->asc.size;
00136 }
00137
00144 static int
00145 androidgrab_read_close(AVFormatContext *s1)
00146 {
00147 return 0;
00148 }
00149
00150 #define OFFSET(x) offsetof(struct androidgrab, x)
00151 #define DEC AV_OPT_FLAG_DECODING_PARAM
00152 static const AVOption options[] = {
00153
00154 { "width", "horizontal size", OFFSET(asc.width), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 4096, DEC },
00155 { "height", "vertical size", OFFSET(asc.height), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 4096, DEC },
00156 { "framerate", "max framerate", OFFSET(framerate), AV_OPT_TYPE_DOUBLE, {.dbl = 60}, 0, 60, DEC },
00157 { NULL },
00158 };
00159
00160 static const AVClass android_class = {
00161 .class_name = "androidgrab indev",
00162 .item_name = av_default_item_name,
00163 .option = options,
00164 .version = LIBAVUTIL_VERSION_INT,
00165 };
00166
00168 AVInputFormat ff_x11grab_demuxer = {
00169 .name = "androidgrab",
00170 .long_name = NULL_IF_CONFIG_SMALL("androidgrab"),
00171 .priv_data_size = sizeof(struct androidgrab),
00172 .read_header = androidgrab_read_header,
00173 .read_packet = androidgrab_read_packet,
00174 .read_close = androidgrab_read_close,
00175 .flags = AVFMT_NOFILE,
00176 .priv_class = &android_class,
00177 };