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: mpeg4-muxer-v16.patch

File mpeg4-muxer-v16.patch, 25.1 KB (added by Antoine Martin, 5 years ago)

updated patch against r13044

  • xpra/codecs/enc_ffmpeg/encoder.pyx

     
    44# later version. See the file COPYING for details.
    55
    66import os
     7import time
    78import weakref
    89from xpra.log import Logger
    910log = Logger("encoder", "ffmpeg")
     
    1718SAVE_TO_FILE = os.environ.get("XPRA_SAVE_TO_FILE")
    1819
    1920
    20 from libc.stdint cimport uint8_t, int64_t
     21from libc.stdint cimport uint8_t, int64_t, uint32_t
    2122
    2223cdef extern from "../../inline.h":
    2324    pass
     
    7475    AVPixelFormat AV_PIX_FMT_GBRP
    7576
    7677
     78cdef extern from "libavformat/avio.h":
     79    ctypedef int AVIODataMarkerType
     80    int AVIO_FLAG_WRITE
     81
     82    ctypedef struct AVIOContext:
     83        const AVClass *av_class
     84        unsigned char *buffer       #Start of the buffer
     85        int buffer_size             #Maximum buffer size
     86        unsigned char *buf_ptr      #Current position in the buffer
     87        unsigned char *buf_end      #End of the data, may be less than
     88                                    #buffer+buffer_size if the read function returned
     89                                    #less data than requested, e.g. for streams where
     90                                    #no more data has been received yet.
     91        int64_t     pos             #position in the file of the current buffer
     92        int         must_flush      #true if the next seek should flush
     93        int         error           #contains the error code or 0 if no error happened
     94        int         seekable
     95        int64_t     maxsize
     96        int         direct
     97        int64_t     bytes_read
     98
     99    AVIOContext *avio_alloc_context(unsigned char *buffer, int buffer_size, int write_flag,
     100                  void *opaque,
     101                  int (*read_packet)(void *opaque, uint8_t *buf, int buf_size),
     102                  int (*write_packet)(void *opaque, uint8_t *buf, int buf_size),
     103                  int64_t (*seek)(void *opaque, int64_t offset, int whence))
     104
     105
    77106cdef extern from "libavcodec/avcodec.h":
    78107    int CODEC_FLAG_UNALIGNED
    79108    int CODEC_FLAG_QSCALE
     
    168197        unsigned int codec_tag
    169198        int64_t bit_rate
    170199
     200    ctypedef struct AVFormatContext:
     201        const AVClass   *av_class
     202        AVOutputFormat  *oformat
     203        void            *priv_data
     204        AVIOContext     *pb
     205        int             ctx_flags
     206        unsigned int    nb_streams
     207        AVStream        **streams
     208        int64_t         start_time
     209        int64_t         duration
     210        int             bit_rate
     211        unsigned int    packet_size
     212        int             max_delay
     213        int             flags
     214        unsigned int    probesize
     215        int             max_analyze_duration
     216        AVCodecID       video_codec_id
     217        AVCodecID       audio_codec_id
     218        AVCodecID       subtitle_codec_id
     219        unsigned int    max_index_size
     220        unsigned int    max_picture_buffer
     221        unsigned int    nb_chapters
     222        AVDictionary    *metadata
     223        int64_t         start_time_realtime
     224        int             strict_std_compliance
     225
     226    ctypedef int AVFieldOrder
     227    ctypedef int AVColorRange
     228    ctypedef int AVColorPrimaries
     229    ctypedef int AVColorTransferCharacteristic
     230    ctypedef int AVColorSpace
     231    ctypedef int AVChromaLocation
     232    ctypedef struct AVCodecParameters:
     233        AVCodecID       codec_id
     234        uint32_t        codec_tag
     235        int64_t         bit_rate
     236        int             bits_per_coded_sample
     237        int             bits_per_raw_sample
     238        int             profile
     239        int             level
     240        int             width
     241        int             height
     242        AVFieldOrder    field_order
     243        AVColorRange    color_range
     244        AVColorPrimaries    color_primaries
     245        AVColorTransferCharacteristic color_trc
     246        AVColorSpace        color_space
     247        AVChromaLocation    chroma_location
     248        int             sample_rate
     249        int             frame_size
     250
    171251    AVCodecID AV_CODEC_ID_H264
    172252    AVCodecID AV_CODEC_ID_H265
    173253    AVCodecID AV_CODEC_ID_VP8
     
    182262    int avcodec_send_frame(AVCodecContext *avctx,const AVFrame *frame) nogil
    183263    int avcodec_receive_packet(AVCodecContext *avctx, AVPacket *avpkt) nogil
    184264
     265    int av_write_frame(AVFormatContext *s, AVPacket *pkt)
    185266    AVFrame* av_frame_alloc()
    186267    void av_frame_free(AVFrame **frame)
    187268    int avcodec_close(AVCodecContext *avctx)
     269    void av_frame_unref(AVFrame *frame) nogil
    188270    void av_init_packet(AVPacket *pkt) nogil
    189271    void av_packet_unref(AVPacket *pkt) nogil
    190272
     
    240322        #AVClassCategory (*get_category)(void *ctx)
    241323
    242324
     325cdef extern from "libavformat/avformat.h":
     326    int AVFMTCTX_NOHEADER           #signal that no header is present
     327
     328    int AVFMT_FLAG_GENPTS           #Generate missing pts even if it requires parsing future frames
     329    int AVFMT_FLAG_IGNIDX           #Ignore index
     330    int AVFMT_FLAG_NONBLOCK         #Do not block when reading packets from input
     331    int AVFMT_FLAG_IGNDTS           #Ignore DTS on frames that contain both DTS & PTS
     332    int AVFMT_FLAG_NOFILLIN         #Do not infer any values from other values, just return what is stored in the container
     333    int AVFMT_FLAG_NOPARSE          #Do not use AVParsers, you also must set AVFMT_FLAG_NOFILLIN as the fillin code works on frames and no parsing -> no frames. Also seeking to frames can not work if parsing to find frame boundaries has been disabled
     334    int AVFMT_FLAG_NOBUFFER         #Do not buffer frames when possible
     335    int AVFMT_FLAG_CUSTOM_IO        #The caller has supplied a custom AVIOContext, don't avio_close() it
     336    int AVFMT_FLAG_DISCARD_CORRUPT  #Discard frames marked corrupted
     337    int AVFMT_FLAG_FLUSH_PACKETS    #Flush the AVIOContext every packet
     338    int AVFMT_FLAG_BITEXACT
     339    int AVFMT_FLAG_MP4A_LATM        #Enable RTP MP4A-LATM payload
     340    int AVFMT_FLAG_SORT_DTS         #try to interleave outputted packets by dts (using this flag can slow demuxing down)
     341    int AVFMT_FLAG_PRIV_OPT         #Enable use of private options by delaying codec open (this could be made default once all code is converted)
     342    int AVFMT_FLAG_KEEP_SIDE_DATA   #Don't merge side data but keep it separate.
     343    int AVFMT_FLAG_FAST_SEEK        #Enable fast, but inaccurate seeks for some formats
     344
     345    int AVFMT_NOFILE                #Demuxer will use avio_open, no opened file should be provided by the caller
     346    int AVFMT_NEEDNUMBER            #Needs '%d' in filename
     347    int AVFMT_SHOW_IDS              #Show format stream IDs numbers
     348    int AVFMT_RAWPICTURE            #Format wants AVPicture structure for raw picture data. @deprecated Not used anymore
     349    int AVFMT_GLOBALHEADER          #Format wants global header
     350    int AVFMT_NOTIMESTAMPS          #Format does not need / have any timestamps
     351    int AVFMT_GENERIC_INDEX         #Use generic index building code
     352    int AVFMT_TS_DISCONT            #Format allows timestamp discontinuities. Note, muxers always require valid (monotone) timestamps
     353    int AVFMT_VARIABLE_FPS          #Format allows variable fps
     354    int AVFMT_NODIMENSIONS          #Format does not need width/height
     355    int AVFMT_NOSTREAMS             #Format does not require any streams
     356    int AVFMT_NOBINSEARCH           #Format does not allow to fall back on binary search via read_timestamp
     357    int AVFMT_NOGENSEARCH           #Format does not allow to fall back on generic search
     358    int AVFMT_NO_BYTE_SEEK          #Format does not allow seeking by bytes
     359    int AVFMT_ALLOW_FLUSH           #Format allows flushing. If not set, the muxer will not receive a NULL packet in the write_packet function
     360    int AVFMT_TS_NONSTRICT          #Format does not require strictly increasing timestamps, but they must still be monotonic
     361    int AVFMT_TS_NEGATIVE           #Format allows muxing negative timestamps.
     362    int AVFMT_SEEK_TO_PTS           #Seeking is based on PTS
     363
     364    ctypedef struct AVStream:
     365        int         index           #stream index in AVFormatContext
     366        int         id
     367        AVCodecContext *codec
     368        AVRational  time_base
     369        int64_t     start_time
     370        int64_t     duration
     371        int64_t     nb_frames       #number of frames in this stream if known or 0
     372        #AVDiscard   discard         #Selects which packets can be discarded at will and do not need to be demuxed.
     373        AVRational  avg_frame_rate
     374        AVCodecParameters *codecpar
     375
     376    ctypedef struct AVOutputFormat:
     377        const char  *name
     378        const char  *long_name
     379        const char  *mime_type
     380        const char  *extensions
     381        AVCodecID   audio_codec
     382        AVCodecID   video_codec
     383        AVCodecID   subtitle_codec
     384        int         flags       #AVFMT_NOFILE, AVFMT_NEEDNUMBER, AVFMT_GLOBALHEADER, AVFMT_NOTIMESTAMPS, AVFMT_VARIABLE_FPS, AVFMT_NODIMENSIONS, AVFMT_NOSTREAMS, AVFMT_ALLOW_FLUSH, AVFMT_TS_NONSTRICT, AVFMT_TS_NEGATIVE More...
     385        int         (*query_codec)(AVCodecID id, int std_compliance)
     386
     387    void av_register_all()
     388    AVOutputFormat *av_oformat_next(const AVOutputFormat *f)
     389    int avformat_alloc_output_context2(AVFormatContext **ctx, AVOutputFormat *oformat, const char *format_name, const char *filename)
     390    void avformat_free_context(AVFormatContext *s)
     391
     392    int avcodec_parameters_from_context(AVCodecParameters *par, const AVCodecContext *codec)
     393    AVStream *avformat_new_stream(AVFormatContext *s, const AVCodec *c)
     394    int avformat_write_header(AVFormatContext *s, AVDictionary **options)
     395    int av_write_trailer(AVFormatContext *s)
     396    int av_write_frame(AVFormatContext *s, AVPacket *pkt)
     397
     398
    243399AV_OPT_TYPES = {
    244400                AV_OPT_TYPE_FLAGS       : "FLAGS",
    245401                AV_OPT_TYPE_INT         : "INT",
     
    267423             AV_PKT_FLAG_CORRUPT    : "CORRUPT",
    268424             }
    269425
     426AVFMTCTX = {
     427            AVFMTCTX_NOHEADER       : "NOHEADER",
     428            }
     429
    270430CODEC_FLAGS = {
    271431               CODEC_FLAG_UNALIGNED         : "UNALIGNED",
    272432               CODEC_FLAG_QSCALE            : "QSCALE",
     
    291451                CODEC_FLAG2_FAST : "FAST",
    292452                }
    293453
     454FMT_FLAGS = {
     455             AVFMT_FLAG_GENPTS          : "GENPTS",
     456             AVFMT_FLAG_IGNIDX          : "IGNIDX",
     457             AVFMT_FLAG_NONBLOCK        : "NONBLOCK",
     458             AVFMT_FLAG_IGNDTS          : "IGNDTS",
     459             AVFMT_FLAG_NOFILLIN        : "NOFILLIN",
     460             AVFMT_FLAG_NOPARSE         : "NOPARSE",
     461             AVFMT_FLAG_NOBUFFER        : "NOBUFFER",
     462             AVFMT_FLAG_CUSTOM_IO       : "CUSTOM_IO",
     463             AVFMT_FLAG_DISCARD_CORRUPT : "DISCARD_CORRUPT",
     464             AVFMT_FLAG_FLUSH_PACKETS   : "FLUSH_PACKETS",
     465             AVFMT_FLAG_BITEXACT        : "BITEXACT",
     466             AVFMT_FLAG_MP4A_LATM       : "MP4A_LATM",
     467             AVFMT_FLAG_SORT_DTS        : "SORT_DTS",
     468             AVFMT_FLAG_PRIV_OPT        : "PRIV_OPT",
     469             AVFMT_FLAG_KEEP_SIDE_DATA  : "KEEP_SIDE_DATA",
     470             AVFMT_FLAG_FAST_SEEK       : "FAST_SEEK",
     471             }
     472
     473AVFMT = {
     474         AVFMT_NOFILE           : "NOFILE",
     475         AVFMT_NEEDNUMBER       : "NEEDNUMBER",
     476         AVFMT_SHOW_IDS         : "SHOW_IDS",
     477         AVFMT_RAWPICTURE       : "RAWPICTURE",
     478         AVFMT_GLOBALHEADER     : "GLOBALHEADER",
     479         AVFMT_NOTIMESTAMPS     : "NOTIMESTAMPS",
     480         AVFMT_GENERIC_INDEX    : "GENERIC_INDEX",
     481         AVFMT_TS_DISCONT       : "TS_DISCONT",
     482         AVFMT_VARIABLE_FPS     : "VARIABLE_FPS",
     483         AVFMT_NODIMENSIONS     : "NODIMENSIONS",
     484         AVFMT_NOSTREAMS        : "NOSTREAMS",
     485         AVFMT_NOBINSEARCH      : "NOBINSEARCH",
     486         AVFMT_NOGENSEARCH      : "NOGENSEARCH",
     487         AVFMT_NO_BYTE_SEEK     : "NO_BYTE_SEEK",
     488         AVFMT_ALLOW_FLUSH      : "ALLOW_FLUSH",
     489         AVFMT_TS_NONSTRICT     : "TS_NONSTRICT",
     490         AVFMT_TS_NEGATIVE      : "TS_NEGATIVE",
     491         AVFMT_SEEK_TO_PTS      : "SEEK_TO_PTS",
     492         }
     493
     494
    294495CAPS = {
    295496        CODEC_CAP_DRAW_HORIZ_BAND       : "DRAW_HORIZ_BAND",
    296497        CODEC_CAP_DR1                   : "DR1",
     
    349550def flagscsv(flag_dict, value=0):
    350551    return csv([v for k,v in flag_dict.items() if k&value])
    351552
     553
     554def get_muxer_formats():
     555    av_register_all()
     556    cdef AVOutputFormat *fmt = NULL
     557    formats = {}
     558    while True:
     559        fmt = av_oformat_next(fmt)
     560        if fmt==NULL:
     561            break
     562        name = fmt.name
     563        long_name = fmt.long_name
     564        formats[name] = long_name
     565    return formats
     566log("AV Output Formats:")
     567print_nested_dict(get_muxer_formats(), print_fn=log.debug)
     568
     569cdef AVOutputFormat* get_av_output_format(name):
     570    cdef AVOutputFormat *fmt = NULL
     571    while True:
     572        fmt = av_oformat_next(fmt)
     573        if fmt==NULL:
     574            break
     575        if name==fmt.name:
     576            return fmt
     577    return NULL
     578
     579
    352580def get_version():
    353581    return (LIBAVCODEC_VERSION_MAJOR, LIBAVCODEC_VERSION_MINOR, LIBAVCODEC_VERSION_MICRO)
    354582
     
    376604    return "error %s" % errnum
    377605
    378606DEF EAGAIN = -11
     607DEF DEFAULT_BUF_LEN = 64*1024
    379608
    380609
    381610def init_module():
     
    398627    return  {
    399628             "version"      : get_version(),
    400629             "encodings"    : get_encodings(),
     630             "muxers"       : get_muxer_formats(),
    401631             "buffer_api"   : get_buffer_api_version(),
    402632             "formats"      : f,
    403633             "generation"   : generation.get(),
     
    416646    return ["YUV420P"]
    417647
    418648
     649GEN_TO_ENCODER = weakref.WeakValueDictionary()
     650
     651
     652cdef list_options(void *obj, const AVClass *av_class):
     653    if av_class==NULL:
     654        return
     655    cdef const AVOption *option = <const AVOption*> av_class.option
     656    options = []
     657    while option!=NULL:
     658        oname = option.name
     659        options.append(oname)
     660        option = av_opt_next(obj, option)
     661    log("%s options: %s", av_class.class_name, csv(options))
     662    cdef void *child = NULL
     663    cdef const AVClass *child_class = NULL
     664    while True:
     665        child = av_opt_child_next(obj, child)
     666        if child==NULL:
     667            return
     668        child_class = (<AVClass**> child)[0]
     669        list_options(child, child_class)
     670
     671
     672cdef int write_packet(void *opaque, uint8_t *buf, int buf_size):
     673    global GEN_TO_ENCODER
     674    encoder = GEN_TO_ENCODER.get(<unsigned long> opaque)
     675    #log.warn("write_packet(%#x, %#x, %#x) encoder=%s", <unsigned long> opaque, <unsigned long> buf, buf_size, type(encoder))
     676    if not encoder:
     677        log.error("Error: write_packet called for unregistered encoder %i!", <unsigned long> opaque)
     678        return -1
     679    return encoder.write_packet(<unsigned long> buf, buf_size)
     680
    419681MAX_WIDTH, MAX_HEIGHT = 4096, 4096
    420682def get_spec(encoding, colorspace):
    421683    assert encoding in get_encodings(), "invalid encoding: %s (must be one of %s" % (encoding, get_encodings())
     
    432694    """
    433695    cdef AVCodecID codec_id
    434696    cdef AVCodec *codec
     697    cdef AVStream *stream
     698    cdef AVFormatContext *format_ctx
     699    cdef unsigned char *buffer
     700    cdef object buffers
     701    cdef int64_t offset
    435702    cdef AVCodecContext *codec_ctx
    436703    cdef AVPixelFormat pix_fmt
    437704    cdef object src_format
     
    441708    cdef unsigned int width
    442709    cdef unsigned int height
    443710    cdef object encoding
     711    cdef object muxer_format
    444712    cdef object file
    445713
    446714    cdef object __weakref__
     
    457725        self.pix_fmt = FORMAT_TO_ENUM.get(src_format, AV_PIX_FMT_NONE)
    458726        if self.pix_fmt==AV_PIX_FMT_NONE:
    459727            raise Exception("invalid pixel format: %s", src_format)
     728        self.buffers = []
    460729
    461730        avcodec_register_all()
    462731        if self.encoding=="h264":
     
    476745            raise Exception("codec %s not found!" % self.encoding)
    477746        log("%s: \"%s\", codec flags: %s", self.codec.name, self.codec.long_name, flagscsv(CAPS, self.codec.capabilities))
    478747
     748        #TODO: the muxer should be configurable
     749        self.muxer_format = "mp4"   #"mov", "f4v"
    479750        cdef int b_frames = 0   #int(options.get("b-frames"))
    480751        try:
    481752            self.init_encoder(b_frames)
     
    487758            log("enc_ffmpeg.Encoder.init_context(%s, %s, %s) self=%s", self.width, self.height, self.src_format, self.get_info())
    488759
    489760    def init_encoder(self, int b_frames):
     761        global GEN_TO_ENCODER
     762        cdef AVOutputFormat *oformat = get_av_output_format(self.muxer_format)
     763        if oformat==NULL:
     764            raise Exception("libavformat does not support %s" % self.muxer_format)
     765        log("init_encoder() AVOutputFormat(%s)=%#x, flags=%s", self.muxer_format, <unsigned long> oformat, flagscsv(AVFMT, oformat.flags))
     766        if oformat.flags & AVFMT_ALLOW_FLUSH==0:
     767            raise Exception("AVOutputFormat(%s) does not support flushing!" % self.muxer_format)
     768        r = avformat_alloc_output_context2(&self.format_ctx, oformat, self.muxer_format, NULL)
     769        if r!=0:
     770            msg = av_error_str(r)
     771            raise Exception("libavformat cannot allocate context: %s" % msg)
     772        log("init_encoder() avformat_alloc_output_context2 returned %i, format context=%#x, flags=%s, ctx_flags=%s", r, <unsigned long> self.format_ctx,
     773            flagscsv(FMT_FLAGS, self.format_ctx.flags), flagscsv(AVFMTCTX, self.format_ctx.ctx_flags))
     774        list_options(self.format_ctx, self.format_ctx.av_class)
     775
     776        cdef int64_t v = 0
     777        r = av_opt_get_int(self.format_ctx, "movflags", AV_OPT_SEARCH_CHILDREN, &v)
     778        if r==0:
     779            log("movflags=%#x", v)
     780            FF_MOV_FLAG_FRAGMENT = 1<<1
     781            v |= FF_MOV_FLAG_FRAGMENT
     782            r = av_opt_set_int(self.format_ctx, "movflags", v, AV_OPT_SEARCH_CHILDREN)
     783            if r!=0:
     784                log.error("Error: failed to set movflags")
     785                log.error(" %s", av_error_str(r))
     786
    490787        cdef unsigned long gen = generation.increase()
     788        GEN_TO_ENCODER[gen] = self
     789        self.buffer = <unsigned char*> av_malloc(DEFAULT_BUF_LEN)
     790        if self.buffer==NULL:
     791            raise Exception("failed to allocate %iKB of memory" % (DEFAULT_BUF_LEN//1024))
     792        self.format_ctx.pb = avio_alloc_context(self.buffer, DEFAULT_BUF_LEN, 1, <void *> gen, NULL, write_packet, NULL)
     793        if self.format_ctx.pb==NULL:
     794            raise Exception("libavformat failed to allocate io context")
     795        log("init_encoder() saving %s stream to bitstream buffer %#x", self.encoding, <unsigned long> self.buffer)
     796        self.format_ctx.bit_rate = 500000
     797        self.format_ctx.start_time_realtime = int(time.time())
    491798
     799        self.stream = avformat_new_stream(self.format_ctx, NULL)    #self.codec
     800        log("init_encoder() avformat_new_stream=%#x, nb streams=%i", <unsigned long> self.stream, self.format_ctx.nb_streams)
     801
    492802        self.codec_ctx = avcodec_alloc_context3(self.codec)
    493803        if self.codec_ctx==NULL:
    494804            raise Exception("failed to allocate codec context!")
     
    510820        self.codec_ctx.thread_safe_callbacks = 1
    511821        self.codec_ctx.thread_type = 2      #FF_THREAD_SLICE: allow more than one thread per frame
    512822        self.codec_ctx.thread_count = 0     #auto
     823        if oformat.flags & AVFMT_GLOBALHEADER:
     824            self.codec_ctx.flags |= CODEC_FLAG_GLOBAL_HEADER
    513825        self.codec_ctx.flags2 |= CODEC_FLAG2_FAST   #may cause "no deblock across slices" - which should be fine
    514826        #av_opt_set(c->priv_data, "preset", "slow", 0)
    515827        log("init_encoder() codec flags: %s", flagscsv(CODEC_FLAGS, self.codec_ctx.flags))
     
    519831        if r!=0:
    520832            raise Exception("could not open %s encoder context: %s" % (self.encoding, av_error_str(r)))
    521833
     834        r = avcodec_parameters_from_context(self.stream.codecpar, self.codec_ctx)
     835        if r<0:
     836            raise Exception("could not copy context parameters %#x: %s" % (<unsigned long> self.stream.codecpar, av_error_str(r)))
     837
     838        log("init_encoder() writing %s header", self.muxer_format)
     839        r = avformat_write_header(self.format_ctx, NULL)
     840        if r!=0:
     841            msg = av_error_str(r)
     842            raise Exception("libavformat failed to write header: %s" % msg)
     843
    522844        self.av_frame = av_frame_alloc()
    523845        if self.av_frame==NULL:
    524846            raise Exception("could not allocate an AVFrame for encoding")
     
    525847        self.frames = 0
    526848
    527849        if SAVE_TO_FILE is not None:
    528             filename = SAVE_TO_FILE+"-"+str(gen)+".%s" % self.encoding
     850            filename = SAVE_TO_FILE+"-"+self.encoding+"-"+str(gen)+".%s" % self.muxer_format
    529851            self.file = open(filename, 'wb')
    530             log.info("saving stream to %s", filename)
     852            log.info("saving %s stream to %s", self.encoding, filename)
    531853
    532854
    533855    def clean(self):
     
    543865        self.width = 0
    544866        self.height = 0
    545867        self.encoding = ""
     868        self.buffers = []
    546869        f = self.file
    547870        if f:
    548871            self.file = None
     
    554877        if self.av_frame!=NULL:
    555878            log("clean_encoder() freeing AVFrame: %#x", <unsigned long> self.av_frame)
    556879            av_frame_free(&self.av_frame)
     880        if self.format_ctx!=NULL:
     881            if self.frames>0:
     882                log("clean_encoder() writing trailer to stream")
     883                av_write_trailer(self.format_ctx)
     884                if self.format_ctx.pb!=NULL:
     885                    av_free(self.format_ctx.pb)
     886                    self.format_ctx.pb = NULL
     887            log("clean_encoder() freeing av format context %#x", <unsigned long> self.format_ctx)
     888            avformat_free_context(self.format_ctx)
     889            self.format_ctx = NULL
     890            log("clean_encoder() freeing bitstream buffer %#x", <unsigned long> self.buffer)
     891            if self.buffer!=NULL:
     892                av_free(self.buffer)
     893                self.buffer = NULL
     894        cdef unsigned long ctx_key          #@DuplicatedSignature
    557895        log("clean_encoder() freeing AVCodecContext: %#x", <unsigned long> self.codec_ctx)
    558896        if self.codec_ctx!=NULL:
    559897            r = avcodec_close(self.codec_ctx)
     
    573911        info = {
    574912                "version"   : get_version(),
    575913                "encoding"  : self.encoding,
     914                "muxer"     : self.muxer_format,
    576915                "formats"   : get_input_colorspaces(self.encoding),
    577916                "type"      : self.get_type(),
    578917                "frames"    : self.frames,
     
    7111050                raise Exception("av packet is corrupt")
    7121051            packet_data = avpkt.data[:avpkt.size]
    7131052            bufs.append(packet_data)
     1053
     1054            avpkt.stream_index = self.stream.index
     1055            r = av_write_frame(self.format_ctx, &avpkt)
     1056            log("av_write_frame packet returned %i", r)
     1057            if ret<0:
     1058                free(avpkt.data)
     1059                self.log_av_error(image, ret, options)
     1060                raise Exception(av_error_str(ret))
     1061            while True:
     1062                r = av_write_frame(self.format_ctx, NULL)
     1063                log("av_write_frame flush returned %i", r)
     1064                if r==1:
     1065                    break
     1066                if ret<0:
     1067                    free(avpkt.data)
     1068                    self.log_av_error(image, ret, options)
     1069                    raise Exception(av_error_str(ret))
    7141070        av_packet_unref(&avpkt)
    7151071        free(avpkt.data)
    7161072        self.frames += 1
    7171073        data = b"".join(bufs)
    7181074        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)
    719         if data and self.file:
    720             self.file.write(data)
     1075        if self.buffers and self.file:
     1076            for x in self.buffers:
     1077                self.file.write(x)
     1078            self.buffers = []
    7211079        return data, client_options
    7221080
    7231081    def flush(self, delayed):
     
    7261084        self.clean()
    7271085        return v
    7281086
     1087    def write_packet(self, unsigned long buf, int buf_size):
     1088        log("write_packet(%#x, %#x)", <unsigned long> buf, buf_size)
     1089        cdef uint8_t *cbuf = <uint8_t*> buf
     1090        buffer = cbuf[:buf_size]
     1091        self.buffers.append(buffer)
     1092        return buf_size
    7291093
     1094
    7301095def selftest(full=False):
    7311096    global CODECS
    7321097    from xpra.codecs.codec_checks import testencoder
  • setup.py

     
    16681668            add_keywords([libffmpeg_bin_dir], [libffmpeg_include_dir],
    16691669                         [libffmpeg_lib_dir, libffmpeg_bin_dir],
    16701670                         ["avcodec", "avutil"])
     1671        if "avformat" in pkgs_options[0]:
     1672            add_keywords([libffmpeg_bin_dir], [libffmpeg_include_dir],
     1673                         [libffmpeg_lib_dir, libffmpeg_bin_dir],
     1674                         ["avformat", "avutil"])
    16711675        elif "swscale" in pkgs_options[0]:
    16721676            add_keywords([libffmpeg_bin_dir], [libffmpeg_include_dir],
    16731677                         [libffmpeg_lib_dir, libffmpeg_bin_dir],
     
    24282432
    24292433toggle_packages(enc_ffmpeg_ENABLED, "xpra.codecs.enc_ffmpeg")
    24302434if enc_ffmpeg_ENABLED:
    2431     ffmpeg_pkgconfig = pkgconfig("libavcodec")
     2435    ffmpeg_pkgconfig = pkgconfig("libavcodec", "libavformat")
    24322436    cython_add(Extension("xpra.codecs.enc_ffmpeg.encoder",
    24332437                ["xpra/codecs/enc_ffmpeg/encoder.pyx"]+membuffers_c,
    24342438                **ffmpeg_pkgconfig))