xpra icon
Bug tracker and wiki

This bug tracker and wiki are being discontinued
please use https://github.com/Xpra-org/xpra instead.


Ticket #1107: enc_ffmpeg-v7.patch

File enc_ffmpeg-v7.patch, 29.4 KB (added by Antoine Martin, 5 years ago)

updated patch for b-frames (#800) and ffmpeg 3.1 (#1242)

  • tests/xpra/codecs/test_enc_ffmpeg.py

     
     1#!/usr/bin/env python
     2# This file is part of Xpra.
     3# Copyright (C) 2013 Antoine Martin <antoine@devloop.org.uk>
     4# Xpra is released under the terms of the GNU GPL v2, or, at your option, any
     5# later version. See the file COPYING for details.
     6
     7from tests.xpra.codecs.test_encoder import test_encoder, test_performance
     8
     9def test_enc_ffmpeg():
     10    print("test_enc_ffmpeg()")
     11    from xpra.codecs.enc_ffmpeg import encoder #@UnresolvedImport
     12    test_encoder(encoder)
     13    #test_performance(encoder)
     14
     15
     16def main():
     17    test_enc_ffmpeg()
     18
     19
     20if __name__ == "__main__":
     21    main()
  • xpra/codecs/codec_checks.py

    Property changes on: tests/xpra/codecs/test_enc_ffmpeg.py
    ___________________________________________________________________
    Added: svn:executable
    ## -0,0 +1 ##
    +*
    \ No newline at end of property
     
    194194                if v is None:
    195195                    raise Exception("%s compression failed" % encoding)
    196196                data, meta = v
    197                 if data is None:
     197                if not data:
    198198                    delayed = meta.get("delayed", 0)
    199199                    assert delayed>0, "data is empty and there are no delayed frames!"
    200200                    #now we should get one:
  • xpra/codecs/enc_ffmpeg/__init__.py

     
     1# This file is part of Xpra.
     2# Copyright (C) 2016 Antoine Martin <antoine@devloop.org.uk>
     3# Xpra is released under the terms of the GNU GPL v2, or, at your option, any
     4# later version. See the file COPYING for details.
  • xpra/codecs/enc_ffmpeg/encoder.pyx

     
     1# This file is part of Xpra.
     2# Copyright (C) 2012-2014 Antoine Martin <antoine@devloop.org.uk>
     3# Xpra is released under the terms of the GNU GPL v2, or, at your option, any
     4# later version. See the file COPYING for details.
     5
     6import os
     7import weakref
     8from xpra.log import Logger
     9log = Logger("encoder", "ffmpeg")
     10
     11from xpra.codecs.image_wrapper import ImageWrapper
     12from xpra.codecs.codec_constants import get_subsampling_divs, video_spec
     13from xpra.codecs.libav_common.av_log cimport override_logger, restore_logger #@UnresolvedImport
     14from xpra.codecs.libav_common.av_log import suspend_nonfatal_logging, resume_nonfatal_logging
     15from xpra.util import AtomicInteger, bytestostr, csv, print_nested_dict
     16
     17SAVE_TO_FILE = os.environ.get("XPRA_SAVE_TO_FILE")
     18
     19
     20from libc.stdint cimport uint8_t, int64_t, uint8_t
     21
     22cdef extern from "string.h":
     23    void free(void * ptr) nogil
     24
     25cdef extern from "../../buffers/buffers.h":
     26    int object_as_buffer(object obj, const void ** buffer, Py_ssize_t * buffer_len)
     27    int get_buffer_api_version()
     28
     29cdef extern from "../../inline.h":
     30    pass
     31
     32cdef extern from "../../buffers/memalign.h":
     33    void *xmemalign(size_t size) nogil
     34
     35
     36cdef extern from "libavutil/mem.h":
     37    void av_free(void *ptr)
     38
     39cdef extern from "libavutil/error.h":
     40    int av_strerror(int errnum, char *errbuf, size_t errbuf_size)
     41
     42cdef extern from "libavcodec/version.h":
     43    int LIBAVCODEC_VERSION_MAJOR
     44    int LIBAVCODEC_VERSION_MINOR
     45    int LIBAVCODEC_VERSION_MICRO
     46
     47#why can't we define this inside the avcodec.h section? (beats me)
     48ctypedef unsigned int AVCodecID
     49ctypedef long AVPixelFormat
     50ctypedef int AVPictureType
     51
     52
     53cdef extern from "libavutil/avutil.h":
     54    int AV_PICTURE_TYPE_NONE
     55    int AV_PICTURE_TYPE_I
     56    int AV_PICTURE_TYPE_P
     57    int AV_PICTURE_TYPE_B
     58    int AV_PICTURE_TYPE_S
     59    int AV_PICTURE_TYPE_SI
     60    int AV_PICTURE_TYPE_SP
     61    int AV_PICTURE_TYPE_BI
     62
     63cdef extern from "libavutil/pixfmt.h":
     64    AVPixelFormat AV_PIX_FMT_NONE
     65    AVPixelFormat AV_PIX_FMT_YUV420P
     66    AVPixelFormat AV_PIX_FMT_YUV422P
     67    AVPixelFormat AV_PIX_FMT_YUV444P
     68    AVPixelFormat AV_PIX_FMT_RGB24
     69    AVPixelFormat AV_PIX_FMT_0RGB
     70    AVPixelFormat AV_PIX_FMT_BGR0
     71    AVPixelFormat AV_PIX_FMT_ARGB
     72    AVPixelFormat AV_PIX_FMT_BGRA
     73    AVPixelFormat AV_PIX_FMT_GBRP
     74
     75cdef extern from "libavcodec/avcodec.h":
     76    int CODEC_FLAG2_FAST
     77    int CODEC_CAP_DRAW_HORIZ_BAND
     78    int CODEC_CAP_DR1
     79    int CODEC_CAP_TRUNCATED
     80    int CODEC_CAP_HWACCEL
     81    int CODEC_CAP_DELAY
     82    int CODEC_CAP_SMALL_LAST_FRAME
     83    int CODEC_CAP_HWACCEL_VDPAU
     84    int CODEC_CAP_SUBFRAMES
     85    int CODEC_CAP_EXPERIMENTAL
     86    int CODEC_CAP_CHANNEL_CONF
     87    int CODEC_CAP_NEG_LINESIZES
     88    int CODEC_CAP_FRAME_THREADS
     89    int CODEC_CAP_SLICE_THREADS
     90    int CODEC_CAP_PARAM_CHANGE
     91    int CODEC_CAP_AUTO_THREADS
     92    int CODEC_CAP_VARIABLE_FRAME_SIZE
     93    int CODEC_CAP_INTRA_ONLY
     94    int CODEC_CAP_LOSSLESS
     95
     96    ctypedef struct AVFrame:
     97        uint8_t **data
     98        int *linesize
     99        int width
     100        int height
     101        int format
     102        int key_frame
     103        int64_t pts
     104        int coded_picture_number
     105        int display_picture_number
     106        int quality
     107        void *opaque
     108        AVPictureType pict_type
     109    ctypedef struct AVCodec:
     110        int capabilities
     111        const char *name
     112        const char *long_name
     113    ctypedef struct AVDictionary:
     114        pass
     115    ctypedef struct AVPacket:
     116        uint8_t *data
     117        int      size
     118
     119    ctypedef struct AVRational:
     120        int num
     121        int den
     122
     123    ctypedef struct AVCodecContext:
     124        int width
     125        int height
     126        AVPixelFormat pix_fmt
     127        int thread_safe_callbacks
     128        int thread_count
     129        int thread_type
     130        int flags
     131        int flags2
     132        int refcounted_frames
     133        int max_b_frames
     134        int has_b_frames
     135        int gop_size
     136        int delay
     137        AVRational framerate
     138        AVRational time_base
     139
     140    ctypedef struct AVFormatContext:
     141        pass
     142
     143    AVCodecID AV_CODEC_ID_H264
     144    AVCodecID AV_CODEC_ID_H265
     145    AVCodecID AV_CODEC_ID_VP8
     146    AVCodecID AV_CODEC_ID_VP9
     147    AVCodecID AV_CODEC_ID_MPEG4
     148
     149    #init and free:
     150    void avcodec_register_all()
     151    AVCodec *avcodec_find_encoder(AVCodecID id)
     152    AVCodecContext *avcodec_alloc_context3(const AVCodec *codec)
     153    int avcodec_open2(AVCodecContext *avctx, const AVCodec *codec, AVDictionary **options)
     154    int avcodec_send_frame(AVCodecContext *avctx,const AVFrame *frame) nogil
     155    int avcodec_receive_packet(AVCodecContext *avctx, AVPacket *avpkt) nogil
     156
     157    int av_write_frame(AVFormatContext *s, AVPacket *pkt)
     158    AVFrame* av_frame_alloc()
     159    void av_frame_free(AVFrame **frame)
     160    int avcodec_close(AVCodecContext *avctx)
     161    void av_frame_unref(AVFrame *frame) nogil
     162    void av_init_packet(AVPacket *pkt) nogil
     163    void av_packet_unref(AVPacket *pkt) nogil
     164
     165
     166CAPS = {
     167        CODEC_CAP_DRAW_HORIZ_BAND       : "DRAW_HORIZ_BAND",
     168        CODEC_CAP_DR1                   : "DR1",
     169        CODEC_CAP_TRUNCATED             : "TRUNCATED",
     170        CODEC_CAP_HWACCEL               : "HWACCEL",
     171        CODEC_CAP_DELAY                 : "DELAY",
     172        CODEC_CAP_SMALL_LAST_FRAME      : "SMALL_LAST_FRAME",
     173        CODEC_CAP_HWACCEL_VDPAU         : "HWACCEL_VDPAU",
     174        CODEC_CAP_SUBFRAMES             : "SUBFRAMES",
     175        CODEC_CAP_EXPERIMENTAL          : "EXPERIMENTAL",
     176        CODEC_CAP_CHANNEL_CONF          : "CHANNEL_CONF",
     177        CODEC_CAP_NEG_LINESIZES         : "NEG_LINESIZES",
     178        CODEC_CAP_FRAME_THREADS         : "FRAME_THREADS",
     179        CODEC_CAP_SLICE_THREADS         : "SLICE_THREADS",
     180        CODEC_CAP_PARAM_CHANGE          : "PARAM_CHANGE",
     181        CODEC_CAP_AUTO_THREADS          : "AUTO_THREADS",
     182        CODEC_CAP_VARIABLE_FRAME_SIZE   : "VARIABLE_FRAME_SIZE",
     183        CODEC_CAP_INTRA_ONLY            : "INTRA_ONLY",
     184        CODEC_CAP_LOSSLESS              : "LOSSLESS",
     185        }
     186log("CODEC_CAP:")
     187print_nested_dict(dict((hex(abs(k)),v) for k,v in CAPS.items()), print_fn=log.debug)
     188
     189PICTURE_TYPE = {
     190                AV_PICTURE_TYPE_NONE    : "NONE",
     191                AV_PICTURE_TYPE_I       : "I",
     192                AV_PICTURE_TYPE_P       : "P",
     193                AV_PICTURE_TYPE_B       : "B",
     194                AV_PICTURE_TYPE_S       : "S",
     195                AV_PICTURE_TYPE_SI      : "SI",
     196                AV_PICTURE_TYPE_SP      : "SP",
     197                AV_PICTURE_TYPE_BI      : "BI",
     198                }
     199log("AV_PICTURE:")
     200print_nested_dict(PICTURE_TYPE, print_fn=log.debug)
     201
     202FORMAT_TO_ENUM = {
     203            "YUV420P"   : AV_PIX_FMT_YUV420P,
     204            "YUV422P"   : AV_PIX_FMT_YUV422P,
     205            "YUV444P"   : AV_PIX_FMT_YUV444P,
     206            "RGB"       : AV_PIX_FMT_RGB24,
     207            "XRGB"      : AV_PIX_FMT_0RGB,
     208            "BGRX"      : AV_PIX_FMT_BGR0,
     209            "ARGB"      : AV_PIX_FMT_ARGB,
     210            "BGRA"      : AV_PIX_FMT_BGRA,
     211            "GBRP"      : AV_PIX_FMT_GBRP,
     212            }
     213
     214COLORSPACES = FORMAT_TO_ENUM.keys()
     215ENUM_TO_FORMAT = {}
     216for pix_fmt, av_enum in FORMAT_TO_ENUM.items():
     217    ENUM_TO_FORMAT[av_enum] = pix_fmt
     218log("AV_PIX_FMT:")
     219print_nested_dict(ENUM_TO_FORMAT, print_fn=log.debug)
     220
     221def get_version():
     222    return (LIBAVCODEC_VERSION_MAJOR, LIBAVCODEC_VERSION_MINOR, LIBAVCODEC_VERSION_MICRO)
     223
     224avcodec_register_all()
     225CODECS = []
     226if avcodec_find_encoder(AV_CODEC_ID_H264)!=NULL:
     227    CODECS.append("h264")
     228#if avcodec_find_encoder(AV_CODEC_ID_VP8)!=NULL:
     229#    CODECS.append("vp8")
     230#if avcodec_find_encoder(AV_CODEC_ID_VP9)!=NULL:
     231#    CODECS.append("vp9")
     232#if avcodec_find_encoder(AV_CODEC_ID_H265)!=NULL:
     233#    CODECS.append("h265")
     234#if avcodec_find_encoder(AV_CODEC_ID_MPEG4)!=NULL:
     235#    CODECS.append("mpeg4")
     236log("enc_ffmpeg.init_module: CODECS=%s", CODECS)
     237
     238cdef av_error_str(int errnum):
     239    cdef char[128] err_str
     240    cdef int i = 0
     241    if av_strerror(errnum, err_str, 128)==0:
     242        while i<128 and err_str[i]!=0:
     243            i += 1
     244        return bytestostr(err_str[:i])
     245    return "error %s" % errnum
     246
     247DEF EAGAIN = -11
     248
     249
     250def init_module():
     251    log("enc_ffmpeg.init_module()")
     252    override_logger()
     253
     254def cleanup_module():
     255    log("enc_ffmpeg.cleanup_module()")
     256    restore_logger()
     257
     258def get_type():
     259    return "ffmpeg"
     260
     261generation = AtomicInteger()
     262def get_info():
     263    global generation
     264    f = {}
     265    for e in get_encodings():
     266        f[e] = get_input_colorspaces(e)
     267    return  {
     268             "version"      : get_version(),
     269             "encodings"    : get_encodings(),
     270             "buffer_api"   : get_buffer_api_version(),
     271             "formats"      : f,
     272             "generation"   : generation.get(),
     273             }
     274
     275def get_encodings():
     276    global CODECS
     277    return CODECS
     278
     279def get_input_colorspaces(encoding):
     280    return ["YUV420P"]
     281
     282def get_output_colorspaces(encoding, csc):
     283    if encoding not in CODECS:
     284        return ""
     285    return ["YUV420P"]
     286
     287
     288MAX_WIDTH, MAX_HEIGHT = 4096, 4096
     289def get_spec(encoding, colorspace):
     290    assert encoding in get_encodings(), "invalid encoding: %s (must be one of %s" % (encoding, get_encodings())
     291    assert colorspace in get_input_colorspaces(encoding), "invalid colorspace: %s (must be one of %s)" % (colorspace, get_input_colorspaces(encoding))
     292    return video_spec(encoding=encoding, output_colorspaces=get_output_colorspaces(encoding, colorspace), has_lossless_mode=False,
     293                            codec_class=Encoder, codec_type=get_type(),
     294                            quality=50, speed=50,
     295                            setup_cost=50, width_mask=0xFFFE, height_mask=0xFFFE, max_w=MAX_WIDTH, max_h=MAX_HEIGHT)
     296
     297
     298cdef class Encoder:
     299    """
     300        This wraps the AVCodecContext and its configuration,
     301    """
     302    cdef AVCodec *codec
     303    cdef AVCodecContext *codec_ctx
     304    cdef AVPixelFormat pix_fmt
     305    cdef object src_format
     306    cdef AVFrame *av_frame
     307    #this is the actual number of images we have returned
     308    cdef unsigned long frames
     309    cdef unsigned int width
     310    cdef unsigned int height
     311    cdef object encoding
     312    cdef object file
     313
     314    cdef object __weakref__
     315
     316    def init_context(self, unsigned int width, unsigned int height, src_format, dst_formats, encoding, int quality, int speed, scaling, options):    #@DuplicatedSignature
     317        global CODECS, generation
     318        assert encoding in CODECS
     319        assert src_format in get_input_colorspaces(encoding), "invalid colorspace: %s" % src_format
     320        self.encoding = encoding
     321        self.width = width
     322        self.height = height
     323        self.src_format = src_format
     324        self.pix_fmt = FORMAT_TO_ENUM.get(src_format, AV_PIX_FMT_NONE)
     325        if self.pix_fmt==AV_PIX_FMT_NONE:
     326            raise Exception("invalid pixel format: %s", src_format)
     327
     328        avcodec_register_all()
     329        cdef AVCodecID CodecID
     330        if self.encoding=="h264":
     331            CodecID = AV_CODEC_ID_H264
     332        elif self.encoding=="h265":
     333            CodecID = AV_CODEC_ID_H265
     334        elif self.encoding=="vp8":
     335            CodecID = AV_CODEC_ID_VP8
     336        elif self.encoding=="vp9":
     337            CodecID = AV_CODEC_ID_VP9
     338        elif self.encoding=="mpeg4":
     339            CodecID = AV_CODEC_ID_MPEG4
     340        else:
     341            raise Exception("invalid codec; %s" % self.encoding)
     342        self.codec = avcodec_find_encoder(CodecID)
     343        if self.codec==NULL:
     344            raise Exception("codec %s not found!" % self.encoding)
     345        log("%s: \"%s\", codec flags: %s", self.codec.name, self.codec.long_name, csv(v for k,v in CAPS.items() if (self.codec.capabilities & k)))
     346
     347        #from here on, we have to call clean_encoder():
     348        self.codec_ctx = avcodec_alloc_context3(self.codec)
     349        if self.codec_ctx==NULL:
     350            self.clean_encoder()
     351            raise Exception("failed to allocate codec context!")
     352
     353        cdef int b_frames = int(options.get("b-frames"))
     354        #we need a framerate.. make one up:
     355        self.codec_ctx.framerate.num = 1
     356        self.codec_ctx.framerate.den = 25
     357        self.codec_ctx.time_base.num = 1
     358        self.codec_ctx.time_base.den = 25
     359        self.codec_ctx.refcounted_frames = 1
     360        self.codec_ctx.max_b_frames = b_frames*1
     361        self.codec_ctx.has_b_frames = b_frames
     362        self.codec_ctx.delay = 0
     363        self.codec_ctx.gop_size = 1
     364        self.codec_ctx.width = width
     365        self.codec_ctx.height = height
     366        self.codec_ctx.pix_fmt = self.pix_fmt
     367        self.codec_ctx.thread_safe_callbacks = 1
     368        self.codec_ctx.thread_type = 2      #FF_THREAD_SLICE: allow more than one thread per frame
     369        self.codec_ctx.thread_count = 0     #auto
     370        self.codec_ctx.flags2 |= CODEC_FLAG2_FAST   #may cause "no deblock across slices" - which should be fine
     371        #av_opt_set(c->priv_data, "preset", "slow", 0)
     372        cdef int r = avcodec_open2(self.codec_ctx, self.codec, NULL)
     373        if r<0:
     374            self.clean_encoder()
     375            raise Exception("could not open %s encoder context: %s" % (self.encoding, av_error_str(r)))
     376        self.av_frame = av_frame_alloc()
     377        if self.av_frame==NULL:
     378            self.clean_encoder()
     379            raise Exception("could not allocate an AVFrame for encoding")
     380        self.frames = 0
     381        log("enc_ffmpeg.Encoder.init_context(%s, %s, %s) self=%s", width, height, src_format, self.get_info())
     382        gen = generation.increase()
     383        if SAVE_TO_FILE is not None:
     384            filename = SAVE_TO_FILE+"ffmpeg-"+self.encoding+"-"+str(gen)+".%s" % encoding
     385            self.file = open(filename, 'wb')
     386            log.info("saving %s stream to %s", encoding, filename)
     387
     388    def clean(self):
     389        self.clean_encoder()
     390        self.codec = NULL
     391        self.pix_fmt = 0
     392        self.src_format = ""
     393        self.av_frame = NULL                        #should be redundant
     394        self.frames = 0
     395        self.width = 0
     396        self.height = 0
     397        self.encoding = ""
     398        f = self.file
     399        if f:
     400            self.file = None
     401            f.close()
     402
     403
     404    def clean_encoder(self):
     405        cdef int r, i
     406        log("%s.clean_encoder()", self)
     407
     408        if self.av_frame!=NULL:
     409            log("clean_encoder() freeing AVFrame: %#x", <unsigned long> self.av_frame)
     410            av_frame_free(&self.av_frame)
     411            #redundant: self.frame = NULL
     412
     413        cdef unsigned long ctx_key          #@DuplicatedSignature
     414        log("clean_encoder() freeing AVCodecContext: %#x", <unsigned long> self.codec_ctx)
     415        if self.codec_ctx!=NULL:
     416            r = avcodec_close(self.codec_ctx)
     417            if r!=0:
     418                log.error("Error: failed to close encoder context %#x", <unsigned long> self.codec_ctx)
     419                log.error(" %s", av_error_str(r))
     420            av_free(self.codec_ctx)
     421            self.codec_ctx = NULL
     422        log("clean_encoder() done")
     423
     424    def __repr__(self):                      #@DuplicatedSignature
     425        if self.is_closed():
     426            return "enc_ffmpeg.Encoder(*closed*)"
     427        return "enc_ffmpeg.Encoder(%s)" % self.get_info()
     428
     429    def get_info(self):                      #@DuplicatedSignature
     430        info = {
     431                "version"   : get_version(),
     432                "encoding"  : self.encoding,
     433                "formats"   : get_input_colorspaces(self.encoding),
     434                "type"      : self.get_type(),
     435                "frames"    : self.frames,
     436                "width"     : self.width,
     437                "height"    : self.height,
     438                }
     439        if self.codec:
     440            info["codec"] = self.codec.name[:]
     441            info["description"] = self.codec.long_name[:]
     442        if self.src_format:
     443            info["src_format"] = self.src_format
     444        if not self.is_closed():
     445            info["encoder_width"] = self.codec_ctx.width
     446            info["encoder_height"] = self.codec_ctx.height
     447        else:
     448            info["closed"] = True
     449        return info
     450
     451    def is_closed(self):
     452        return self.codec_ctx==NULL
     453
     454    def __dealloc__(self):                          #@DuplicatedSignature
     455        self.clean()
     456
     457    def get_width(self):
     458        return self.width
     459
     460    def get_height(self):
     461        return self.height
     462
     463    def get_src_format(self):
     464        return self.src_format
     465
     466    def get_encoding(self):
     467        return self.encoding
     468
     469    def get_type(self):                             #@DuplicatedSignature
     470        return "ffmpeg"
     471
     472    def get_delayed_frames(self):
     473        return 0
     474
     475    def log_av_error(self, image, err_no, options={}):
     476        msg = av_error_str(err_no)
     477        self.log_error(image, msg, options, "error %i" % err_no)
     478
     479    def log_error(self, image, err, options={}, error_type="error"):
     480        log.error("Error: ffmpeg %s encoding %s:", error_type, self.encoding)
     481        log.error(" '%s'", err)
     482        log.error(" on image %s", image)
     483        log.error(" frame %i", self.frames)
     484        if options:
     485            log.error(" options=%s", options)
     486        log.error(" encoder state:")
     487        for k,v in self.get_info().items():
     488            log.error("  %s = %s", k, v)
     489
     490    def compress_image(self, image, int quality=-1, int speed=-1, options={}):
     491        cdef unsigned char * padded_buf = NULL
     492        cdef const unsigned char * buf = NULL
     493        cdef Py_ssize_t buf_len = 0
     494        cdef int ret
     495        cdef AVPacket avpkt
     496        cdef AVFrame *frame
     497        assert self.codec_ctx!=NULL, "no codec context! (not initialized or already closed)"
     498        assert self.codec!=NULL
     499
     500        if image:
     501            pixels = image.get_pixels()
     502            istrides = image.get_rowstride()
     503            assert len(pixels)==3, "image pixels does not have 3 planes! (found %s)" % len(pixels)
     504            assert len(istrides)==3, "image strides does not have 3 values! (found %s)" % len(istrides)
     505   
     506            #populate the avframe:
     507            for i in range(4):
     508                if i<3:
     509                    assert object_as_buffer(pixels[i], <const void**> &buf, &buf_len)==0, "unable to convert %s to a buffer (plane=%s)" % (type(pixels[i]), i)
     510                    #log("plane %s: %i bytes (%ix%i stride=%i)", ["Y", "U", "V"][i], buf_len, self.width, self.height, istrides[i])
     511                    self.av_frame.data[i] = <uint8_t *> buf
     512                    self.av_frame.linesize[i] = istrides[i]
     513                else:
     514                    self.av_frame.data[i] = NULL
     515            self.av_frame.width = self.width
     516            self.av_frame.height = self.height
     517            self.av_frame.format = self.pix_fmt
     518            self.av_frame.pts = self.frames+1
     519            self.av_frame.coded_picture_number = self.frames+1
     520            self.av_frame.display_picture_number = self.frames+1
     521            if self.frames==0:
     522                self.av_frame.pict_type = AV_PICTURE_TYPE_I
     523            else:
     524                self.av_frame.pict_type = AV_PICTURE_TYPE_P
     525            #self.av_frame.quality = 1
     526            frame = self.av_frame
     527        else:
     528            assert options.get("flush")
     529            frame = NULL
     530
     531        with nogil:
     532            ret = avcodec_send_frame(self.codec_ctx, frame)
     533        if ret!=0:
     534            self.log_av_error(image, ret, options)
     535            raise Exception(av_error_str(ret))
     536
     537        buf_len = 1024+self.width*self.height
     538        av_init_packet(&avpkt)
     539        avpkt.data = <uint8_t *> xmemalign(buf_len)
     540        avpkt.size = buf_len
     541        assert ret==0
     542        bufs = []
     543        client_options = {}
     544        while ret==0:
     545            with nogil:
     546                ret = avcodec_receive_packet(self.codec_ctx, &avpkt)
     547            if ret==EAGAIN:
     548                client_options["delayed"] = 1
     549                log("ffmpeg EAGAIN: delayed picture")
     550                break
     551            if ret!=0 and bufs:
     552                break
     553            if ret<0:
     554                free(avpkt.data)
     555                self.log_av_error(image, ret, options)
     556                raise Exception(av_error_str(ret))
     557            if ret>0:
     558                free(avpkt.data)
     559                self.log_error(image, ret, options, "no stream")
     560                raise Exception("no stream")
     561            log("avcodec_receive_packet returned %#x bytes of data", avpkt.size)
     562            packet_data = avpkt.data[:avpkt.size]
     563            bufs.append(packet_data)
     564            if self.file and packet_data:
     565                self.file.write(packet_data)
     566                self.file.flush()
     567        av_packet_unref(&avpkt)
     568        free(avpkt.data)
     569        self.frames += 1
     570        data = b"".join(bufs)
     571        log("compress_image(%s) %5i bytes (%i buffers) for %4s frame %-3i, client options: %s", image, len(data), len(bufs), self.encoding, self.frames, client_options)
     572        return data, client_options
     573
     574    def flush(self, delayed):
     575        return self.compress_image(None, options={"flush" : True})
     576
     577
     578def selftest(full=False):
     579    global CODECS
     580    from xpra.codecs.codec_checks import testencoder
     581    from xpra.codecs.enc_ffmpeg import encoder
     582    try:
     583        suspend_nonfatal_logging()
     584        CODECS = testencoder(encoder, full)
     585    finally:
     586        resume_nonfatal_logging()
  • xpra/codecs/loader.py

     
    5252        return None
    5353    try:
    5454        #module is present
     55        classname = "?"
    5556        try:
    5657            log(" %s found, will check for %s in %s", top_module, classnames, class_module)
    5758            for classname in classnames:
    5859                ic =  __import__(class_module, {}, {}, classname)
    59                 selftest = getattr(ic, "selftest", None)
    60                 log("%s.selftest=%s", name, selftest)
    61                 if SELFTEST and selftest:
    62                     if name in CODEC_FAIL_SELFTEST:
    63                         raise ImportError("codec found in fail selftest list")
    64                     try:
    65                         selftest(FULL_SELFTEST)
    66                     except Exception as e:
    67                         log.warn("Warning: %s failed its self test", name)
    68                         log.warn(" %s", e)
    69                         log("%s failed", selftest, exc_info=True)
    70                         continue
     60                try:
     61                    #run init_module?
     62                    init_module = getattr(ic, "init_module", None)
     63                    log("%s: init_module=%s", class_module, init_module)
     64                    if init_module:
     65                        init_module()
     66                    selftest = getattr(ic, "selftest", None)
     67                    log("%s.selftest=%s", name, selftest)
     68                    if SELFTEST and selftest:
     69                        if name in CODEC_FAIL_SELFTEST:
     70                            raise ImportError("codec found in fail selftest list")
     71                        try:
     72                            selftest(FULL_SELFTEST)
     73                        except Exception as e:
     74                            log.warn("Warning: %s failed its self test", name)
     75                            log.warn(" %s", e)
     76                            log("%s failed", selftest, exc_info=True)
     77                            continue
     78                finally:
     79                    cleanup_module = getattr(ic, "cleanup_module", None)
     80                    log("%s: cleanup_module=%s", class_module, cleanup_module)
     81                    if cleanup_module:
     82                        cleanup_module()
    7183                #log.warn("codec_import_check(%s, ..)=%s" % (name, ic))
    7284                log(" found %s : %s", name, ic)
    7385                codecs[name] = ic
     
    157169        codec_import_check("xvid", "xvid encoder", "xpra.codecs.xvid", "xpra.codecs.xvid.encoder", "Encoder")
    158170        add_codec_version("xvid", "xpra.codecs.xvid.encoder")
    159171
     172        codec_import_check("enc_ffmpeg", "ffmpeg encoder", "xpra.codecs.enc_ffmpeg", "xpra.codecs.enc_ffmpeg.encoder", "Encoder")
     173        add_codec_version("ffmpeg", "xpra.codecs.enc_ffmpeg.encoder")
     174
    160175    if csc:
    161176        show += list(CSC_CODECS)
    162177        codec_import_check("csc_swscale", "swscale colorspace conversion", "xpra.codecs.csc_swscale", "xpra.codecs.csc_swscale.colorspace_converter", "ColorspaceConverter")
  • xpra/codecs/video_helper.py

     
    1818
    1919#the codec loader uses the names...
    2020#but we need the module name to be able to probe without loading the codec:
    21 CODEC_TO_MODULE = {"vpx"        : ["vpx"],
     21CODEC_TO_MODULE = {
     22                   "vpx"        : ["vpx"],
    2223                   "x264"       : ["enc_x264"],
    2324                   "x265"       : ["enc_x265"],
    2425                   "nvenc"      : NVENC_OPTIONS,
     
    2829                   "opencl"     : ["csc_opencl"],
    2930                   "opencv"     : ["csc_opencv"],
    3031                   "libyuv"     : ["csc_libyuv"],
    31                    "avcodec2"   : ["dec_avcodec2"]}
     32                   "avcodec2"   : ["dec_avcodec2"],
     33                   "ffmpeg"     : ["enc_ffmpeg"],
     34                   }
    3235
    3336def has_codec_module(module_name):
    3437    top_module = "xpra.codecs.%s" % module_name
     
    5255
    5356#all the codecs we know about:
    5457#try to import the module that contains them (cheap check):
    55 ALL_VIDEO_ENCODER_OPTIONS = try_import_modules(["x264", "vpx", "xvid", "x265", "nvenc"])
     58ALL_VIDEO_ENCODER_OPTIONS = try_import_modules(["x264", "vpx", "xvid", "x265", "nvenc", "ffmpeg"])
    5659ALL_CSC_MODULE_OPTIONS = try_import_modules(["swscale", "cython", "opencl", "libyuv", "opencv"])
    5760NO_GFX_CSC_OPTIONS = [x for x in ALL_CSC_MODULE_OPTIONS if x not in ("opencl", )]
    5861ALL_VIDEO_DECODER_OPTIONS = try_import_modules(["avcodec2", "vpx"])
  • xpra/log.py

     
    196196                ("decoder"      , "All decoders"),
    197197                ("encoder"      , "All encoders"),
    198198                ("avcodec"      , "avcodec decoder"),
    199                 ("libav"        , "libav common code (swscale and avcodec)"),
     199                ("libav"        , "libav common code (used by swscale, avcodec and ffmpeg)"),
     200                ("ffmpeg"       , "ffmpeg encoder"),
    200201                ("pillow"       , "Pillow encoder and decoder"),
    201202                ("vpx"          , "libvpx encoder and decoder"),
    202203                ("nvenc"        , "nvenc encoder (all versions)"),
  • xpra/server/window/window_video_source.py

     
    16411641            flush_delay = max(100, min(500, int(self.batch_config.delay*10)))
    16421642            videolog("schedule video_encoder_flush for encoder %s, last frame=%i, client_options=%s, flush delay=%i", ve, last_frame, client_options, flush_delay)
    16431643            self.b_frame_flush_timer = self.timeout_add(flush_delay, self.flush_video_encoder, ve, csc, last_frame, x, y)
    1644             if data is None:
     1644            if not data:
    16451645                if last_frame==0:
    16461646                    #first frame, just send something:
    16471647                    return self.video_fallback(image, options, order=FAST_ORDER)