]> git.sesse.net Git - ffmpeg/blobdiff - libavdevice/fbdev.c
movenc: Handle pts == NOPTS when autoflushing
[ffmpeg] / libavdevice / fbdev.c
index 58b3ab4572020bba66ff8288db325274ffa64cd8..16469c56d3f1f994256d5770e1a965fa0eafd832 100644 (file)
  * @file
  * Linux framebuffer input device,
  * inspired by code from fbgrab.c by Gunnar Monell.
- * See also http://linux-fbdev.sourceforge.net/.
+ * @see http://linux-fbdev.sourceforge.net/
  */
 
-/* #define DEBUG */
-
 #include <unistd.h>
 #include <fcntl.h>
 #include <sys/ioctl.h>
-#include <sys/time.h>
 #include <sys/mman.h>
 #include <time.h>
 #include <linux/fb.h>
 
+#include "libavutil/internal.h"
 #include "libavutil/log.h"
 #include "libavutil/mem.h"
 #include "libavutil/opt.h"
+#include "libavutil/time.h"
 #include "libavutil/parseutils.h"
 #include "libavutil/pixdesc.h"
 #include "libavformat/avformat.h"
+#include "libavformat/internal.h"
 
 struct rgb_pixfmt_map_entry {
     int bits_per_pixel;
     int red_offset, green_offset, blue_offset, alpha_offset;
-    enum PixelFormat pixfmt;
+    enum AVPixelFormat pixfmt;
 };
 
 static struct rgb_pixfmt_map_entry rgb_pixfmt_map[] = {
     // bpp, red_offset,  green_offset, blue_offset, alpha_offset, pixfmt
-    {  32,       0,           8,          16,           24,   PIX_FMT_RGBA  },
-    {  32,      16,           8,           0,           24,   PIX_FMT_BGRA  },
-    {  32,       8,          16,          24,            0,   PIX_FMT_ARGB  },
-    {  32,       3,           2,           8,            0,   PIX_FMT_ABGR  },
-    {  24,       0,           8,          16,            0,   PIX_FMT_RGB24 },
-    {  24,      16,           8,           0,            0,   PIX_FMT_BGR24 },
+    {  32,       0,           8,          16,           24,   AV_PIX_FMT_RGBA  },
+    {  32,      16,           8,           0,           24,   AV_PIX_FMT_BGRA  },
+    {  32,       8,          16,          24,            0,   AV_PIX_FMT_ARGB  },
+    {  32,       3,           2,           8,            0,   AV_PIX_FMT_ABGR  },
+    {  24,       0,           8,          16,            0,   AV_PIX_FMT_RGB24 },
+    {  24,      16,           8,           0,            0,   AV_PIX_FMT_BGR24 },
+    {  16,      11,           5,           0,            0,   AV_PIX_FMT_RGB565 },
 };
 
-static enum PixelFormat get_pixfmt_from_fb_varinfo(struct fb_var_screeninfo *varinfo)
+static enum AVPixelFormat get_pixfmt_from_fb_varinfo(struct fb_var_screeninfo *varinfo)
 {
     int i;
 
@@ -73,18 +74,18 @@ static enum PixelFormat get_pixfmt_from_fb_varinfo(struct fb_var_screeninfo *var
             return entry->pixfmt;
     }
 
-    return PIX_FMT_NONE;
+    return AV_PIX_FMT_NONE;
 }
 
-typedef struct {
+typedef struct FBDevContext {
     AVClass *class;          ///< class for private options
     int frame_size;          ///< size in bytes of a grabbed frame
-    AVRational fps;          ///< framerate
+    AVRational framerate_q;  ///< framerate
     char *framerate;         ///< framerate string set by a private option
     int64_t time_frame;      ///< time for the next frame to output (in 1/1000000 units)
 
     int fd;                  ///< framebuffer device file descriptor
-    int width, heigth;       ///< assumed frame resolution
+    int width, height;       ///< assumed frame resolution
     int frame_linesize;      ///< linesize of the output frame, it is assumed to be constant
     int bytes_per_pixel;
 
@@ -94,57 +95,55 @@ typedef struct {
     uint8_t *data;           ///< framebuffer data
 } FBDevContext;
 
-av_cold static int fbdev_read_header(AVFormatContext *avctx,
-                                     AVFormatParameters *ap)
+static av_cold int fbdev_read_header(AVFormatContext *avctx)
 {
     FBDevContext *fbdev = avctx->priv_data;
     AVStream *st = NULL;
-    enum PixelFormat pix_fmt;
+    enum AVPixelFormat pix_fmt;
     int ret, flags = O_RDONLY;
+    char errbuf[128];
 
-    ret = av_parse_video_rate(&fbdev->fps, fbdev->framerate);
-    av_freep(&fbdev->framerate);
+    ret = av_parse_video_rate(&fbdev->framerate_q, fbdev->framerate);
     if (ret < 0) {
-        av_log(avctx, AV_LOG_ERROR, "Couldn't parse framerate.\n");
+        av_log(avctx, AV_LOG_ERROR, "Could not parse framerate '%s'.\n", fbdev->framerate);
         return ret;
     }
-#if FF_API_FORMAT_PARAMETERS
-    if (ap->time_base.num)
-        fbdev->fps = (AVRational){ap->time_base.den, ap->time_base.num};
-#endif
 
-    if (!(st = av_new_stream(avctx, 0)))
+    if (!(st = avformat_new_stream(avctx, NULL)))
         return AVERROR(ENOMEM);
-    av_set_pts_info(st, 64, 1, 1000000); /* 64 bits pts in microseconds */
+    avpriv_set_pts_info(st, 64, 1, 1000000); /* 64 bits pts in microseconds */
 
     /* NONBLOCK is ignored by the fbdev driver, only set for consistency */
     if (avctx->flags & AVFMT_FLAG_NONBLOCK)
         flags |= O_NONBLOCK;
 
-    if ((fbdev->fd = open(avctx->filename, flags)) == -1) {
+    if ((fbdev->fd = avpriv_open(avctx->filename, flags)) == -1) {
         ret = AVERROR(errno);
+        av_strerror(ret, errbuf, sizeof(errbuf));
         av_log(avctx, AV_LOG_ERROR,
                "Could not open framebuffer device '%s': %s\n",
-               avctx->filename, strerror(ret));
+               avctx->filename, errbuf);
         return ret;
     }
 
     if (ioctl(fbdev->fd, FBIOGET_VSCREENINFO, &fbdev->varinfo) < 0) {
         ret = AVERROR(errno);
+        av_strerror(ret, errbuf, sizeof(errbuf));
         av_log(avctx, AV_LOG_ERROR,
-               "FBIOGET_VSCREENINFO: %s\n", strerror(errno));
+               "FBIOGET_VSCREENINFO: %s\n", errbuf);
         goto fail;
     }
 
     if (ioctl(fbdev->fd, FBIOGET_FSCREENINFO, &fbdev->fixinfo) < 0) {
         ret = AVERROR(errno);
+        av_strerror(ret, errbuf, sizeof(errbuf));
         av_log(avctx, AV_LOG_ERROR,
-               "FBIOGET_FSCREENINFO: %s\n", strerror(errno));
+               "FBIOGET_FSCREENINFO: %s\n", errbuf);
         goto fail;
     }
 
     pix_fmt = get_pixfmt_from_fb_varinfo(&fbdev->varinfo);
-    if (pix_fmt == PIX_FMT_NONE) {
+    if (pix_fmt == AV_PIX_FMT_NONE) {
         ret = AVERROR(EINVAL);
         av_log(avctx, AV_LOG_ERROR,
                "Framebuffer pixel format not supported.\n");
@@ -152,33 +151,34 @@ av_cold static int fbdev_read_header(AVFormatContext *avctx,
     }
 
     fbdev->width           = fbdev->varinfo.xres;
-    fbdev->heigth          = fbdev->varinfo.yres;
+    fbdev->height          = fbdev->varinfo.yres;
     fbdev->bytes_per_pixel = (fbdev->varinfo.bits_per_pixel + 7) >> 3;
     fbdev->frame_linesize  = fbdev->width * fbdev->bytes_per_pixel;
-    fbdev->frame_size      = fbdev->frame_linesize * fbdev->heigth;
+    fbdev->frame_size      = fbdev->frame_linesize * fbdev->height;
     fbdev->time_frame      = AV_NOPTS_VALUE;
     fbdev->data = mmap(NULL, fbdev->fixinfo.smem_len, PROT_READ, MAP_SHARED, fbdev->fd, 0);
     if (fbdev->data == MAP_FAILED) {
         ret = AVERROR(errno);
-        av_log(avctx, AV_LOG_ERROR, "Error in mmap(): %s\n", strerror(errno));
+        av_strerror(ret, errbuf, sizeof(errbuf));
+        av_log(avctx, AV_LOG_ERROR, "Error in mmap(): %s\n", errbuf);
         goto fail;
     }
 
-    st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
-    st->codec->codec_id   = CODEC_ID_RAWVIDEO;
-    st->codec->width      = fbdev->width;
-    st->codec->height     = fbdev->heigth;
-    st->codec->pix_fmt    = pix_fmt;
-    st->codec->time_base  = ap->time_base;
-    st->codec->bit_rate   =
-        fbdev->width * fbdev->heigth * fbdev->bytes_per_pixel * av_q2d(fbdev->fps) * 8;
+    st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
+    st->codecpar->codec_id   = AV_CODEC_ID_RAWVIDEO;
+    st->codecpar->width      = fbdev->width;
+    st->codecpar->height     = fbdev->height;
+    st->codecpar->format     = pix_fmt;
+    st->codecpar->bit_rate   =
+        fbdev->width * fbdev->height * fbdev->bytes_per_pixel * av_q2d(fbdev->framerate_q) * 8;
+    st->avg_frame_rate  = fbdev->framerate_q;
 
     av_log(avctx, AV_LOG_INFO,
            "w:%d h:%d bpp:%d pixfmt:%s fps:%d/%d bit_rate:%d\n",
-           fbdev->width, fbdev->heigth, fbdev->varinfo.bits_per_pixel,
-           av_pix_fmt_descriptors[pix_fmt].name,
-           fbdev->fps.num, fbdev->fps.den,
-           st->codec->bit_rate);
+           fbdev->width, fbdev->height, fbdev->varinfo.bits_per_pixel,
+           av_get_pix_fmt_name(pix_fmt),
+           fbdev->framerate_q.num, fbdev->framerate_q.den,
+           st->codecpar->bit_rate);
     return 0;
 
 fail:
@@ -200,7 +200,7 @@ static int fbdev_read_packet(AVFormatContext *avctx, AVPacket *pkt)
     /* wait based on the frame rate */
     curtime = av_gettime();
     delay = fbdev->time_frame - curtime;
-    av_dlog(avctx,
+    av_log(avctx, AV_LOG_TRACE,
             "time_frame:%"PRId64" curtime:%"PRId64" delay:%"PRId64"\n",
             fbdev->time_frame, curtime, delay);
     if (delay > 0) {
@@ -211,15 +211,18 @@ static int fbdev_read_packet(AVFormatContext *avctx, AVPacket *pkt)
         while (nanosleep(&ts, &ts) < 0 && errno == EINTR);
     }
     /* compute the time of the next frame */
-    fbdev->time_frame += INT64_C(1000000) / av_q2d(fbdev->fps);
+    fbdev->time_frame += INT64_C(1000000) / av_q2d(fbdev->framerate_q);
 
     if ((ret = av_new_packet(pkt, fbdev->frame_size)) < 0)
         return ret;
 
     /* refresh fbdev->varinfo, visible data position may change at each call */
-    if (ioctl(fbdev->fd, FBIOGET_VSCREENINFO, &fbdev->varinfo) < 0)
+    if (ioctl(fbdev->fd, FBIOGET_VSCREENINFO, &fbdev->varinfo) < 0) {
+        char errbuf[128];
+        av_strerror(AVERROR(errno), errbuf, sizeof(errbuf));
         av_log(avctx, AV_LOG_WARNING,
-               "Error refreshing variable info: %s\n", strerror(errno));
+               "Error refreshing variable info: %s\n", errbuf);
+    }
 
     pkt->pts = curtime;
 
@@ -229,7 +232,7 @@ static int fbdev_read_packet(AVFormatContext *avctx, AVPacket *pkt)
     pout = pkt->data;
 
     // TODO it'd be nice if the lines were aligned
-    for (i = 0; i < fbdev->heigth; i++) {
+    for (i = 0; i < fbdev->height; i++) {
         memcpy(pout, pin, fbdev->frame_linesize);
         pin  += fbdev->fixinfo.line_length;
         pout += fbdev->frame_linesize;
@@ -238,7 +241,7 @@ static int fbdev_read_packet(AVFormatContext *avctx, AVPacket *pkt)
     return fbdev->frame_size;
 }
 
-av_cold static int fbdev_read_close(AVFormatContext *avctx)
+static av_cold int fbdev_read_close(AVFormatContext *avctx)
 {
     FBDevContext *fbdev = avctx->priv_data;
 
@@ -251,7 +254,7 @@ av_cold static int fbdev_read_close(AVFormatContext *avctx)
 #define OFFSET(x) offsetof(FBDevContext, x)
 #define DEC AV_OPT_FLAG_DECODING_PARAM
 static const AVOption options[] = {
-    { "framerate","", OFFSET(framerate), FF_OPT_TYPE_STRING, {.str = "25"}, 0, 0, DEC },
+    { "framerate","", OFFSET(framerate), AV_OPT_TYPE_STRING, {.str = "25"}, 0, 0, DEC },
     { NULL },
 };