xpra icon
Bug tracker and wiki

Ticket #1107: mpeg4-muxer-v9.patch

File mpeg4-muxer-v9.patch, 42.6 KB (added by Antoine Martin, 3 years ago)

muxing work if you use pointers as unsigned long, gets mangled otherwise..

  • setup.py

     
    16511651            add_keywords([libffmpeg_bin_dir], [libffmpeg_include_dir],
    16521652                         [libffmpeg_lib_dir, libffmpeg_bin_dir],
    16531653                         ["avcodec", "avutil"])
     1654        if "avformat" in pkgs_options[0]:
     1655            add_keywords([libffmpeg_bin_dir], [libffmpeg_include_dir],
     1656                         [libffmpeg_lib_dir, libffmpeg_bin_dir],
     1657                         ["avformat", "avutil"])
    16541658        elif "swscale" in pkgs_options[0]:
    16551659            add_keywords([libffmpeg_bin_dir], [libffmpeg_include_dir],
    16561660                         [libffmpeg_lib_dir, libffmpeg_bin_dir],
     
    24112415
    24122416toggle_packages(enc_ffmpeg_ENABLED, "xpra.codecs.enc_ffmpeg")
    24132417if enc_ffmpeg_ENABLED:
    2414     ffmpeg_pkgconfig = pkgconfig("libavcodec")
     2418    ffmpeg_pkgconfig = pkgconfig("libavcodec", "libavformat")
    24152419    cython_add(Extension("xpra.codecs.enc_ffmpeg.encoder",
    24162420                ["xpra/codecs/enc_ffmpeg/encoder.pyx"]+membuffers_c,
    24172421                **ffmpeg_pkgconfig))
  • xpra/codecs/enc_ffmpeg/encoder.pyx

     
    66import os
    77import weakref
    88from xpra.log import Logger
     9from Cython.Shadow import NULL
    910log = Logger("encoder", "ffmpeg")
    1011
    1112from xpra.codecs.image_wrapper import ImageWrapper
     
    1718SAVE_TO_FILE = os.environ.get("XPRA_SAVE_TO_FILE")
    1819
    1920
    20 from libc.stdint cimport uint8_t, int64_t, uint8_t
     21DEF SEEK_SET = 0
     22DEF SEEK_CUR = 1
     23DEF SEEK_END = 2
     24SEEKS = {
     25         SEEK_SET   : "SET",
     26         SEEK_CUR   : "CUR",
     27         SEEK_END   : "END",
     28         }
    2129
     30from libc.stdint cimport uint8_t, int64_t, uint64_t, uint32_t, uint8_t
     31
    2232cdef extern from "string.h":
     33    void *memcpy(void * destination, void *source, size_t num)
    2334    void free(void * ptr) nogil
    2435
    2536cdef extern from "../../buffers/buffers.h":
     
    3546
    3647cdef extern from "libavutil/mem.h":
    3748    void av_free(void *ptr)
     49    void *av_malloc(size_t size)
    3850
    3951cdef extern from "libavutil/error.h":
    4052    int av_strerror(int errnum, char *errbuf, size_t errbuf_size)
     
    7284    AVPixelFormat AV_PIX_FMT_BGRA
    7385    AVPixelFormat AV_PIX_FMT_GBRP
    7486
     87
     88cdef extern from "libavformat/avio.h":
     89    ctypedef int AVIODataMarkerType
     90    int AVIO_FLAG_WRITE
     91
     92    ctypedef struct AVIOInterruptCB:
     93        pass
     94
     95    ctypedef struct AVIOContext:
     96        const AVClass *av_class
     97        unsigned char *buffer       #Start of the buffer
     98        int buffer_size             #Maximum buffer size
     99        unsigned char *buf_ptr      #Current position in the buffer
     100        unsigned char *buf_end      #End of the data, may be less than
     101                                    #buffer+buffer_size if the read function returned
     102                                    #less data than requested, e.g. for streams where
     103                                    #no more data has been received yet.
     104        void *opaque                #A private pointer, passed to the read/write/seek/... functions.
     105        int         (*read_packet)(void *opaque, uint8_t *buf, int buf_size)
     106        int         (*write_packet)(void *opaque, uint8_t *buf, int buf_size)
     107        int64_t     (*seek)(void *opaque, int64_t offset, int whence)
     108        int64_t     pos             #position in the file of the current buffer
     109        int         must_flush      #true if the next seek should flush
     110        int         eof_reached     #true if eof reached
     111        int         write_flag      #true if open for writing
     112        int         max_packet_size
     113        unsigned long checksum
     114        unsigned char *checksum_ptr
     115        unsigned long (*update_checksum)(unsigned long checksum, const uint8_t *buf, unsigned int size)
     116        int         error           #contains the error code or 0 if no error happened
     117        int         (*read_pause)(void *opaque, int pause)
     118        int64_t     (*read_seek)(void *opaque, int stream_index, int64_t timestamp, int flags)
     119        int         seekable
     120        int64_t     maxsize
     121        int         direct
     122        int64_t     bytes_read
     123        int         seek_count;
     124        int         writeout_count
     125        int         orig_buffer_size
     126        int         short_seek_threshold
     127        const char  *protocol_whitelist
     128        const char  *protocol_blacklist
     129        int         (*write_data_type)(void *opaque, uint8_t *buf, int buf_size, AVIODataMarkerType type, int64_t time)
     130        int         ignore_boundary_point
     131        AVIODataMarkerType current_type
     132        int64_t     last_time
     133
     134    AVIOContext *avio_alloc_context(unsigned char *buffer, int buffer_size, int write_flag,
     135                  void *opaque,
     136                  int (*read_packet)(void *opaque, uint8_t *buf, int buf_size),
     137                  int (*write_packet)(void *opaque, uint8_t *buf, int buf_size),
     138                  int64_t (*seek)(void *opaque, int64_t offset, int whence))
     139
     140    int avio_open(AVIOContext **s, const char *url, int flags)
     141    int avio_close(AVIOContext *s)
     142
     143
    75144cdef extern from "libavcodec/avcodec.h":
     145    int CODEC_FLAG_UNALIGNED
     146    int CODEC_FLAG_QSCALE
     147    int CODEC_FLAG_4MV
     148    int CODEC_FLAG_OUTPUT_CORRUPT
     149    int CODEC_FLAG_QPEL
     150    int CODEC_FLAG_GMC
     151    int CODEC_FLAG_MV0
     152    int CODEC_FLAG_INPUT_PRESERVED
     153    int CODEC_FLAG_PASS1
     154    int CODEC_FLAG_PASS2
     155    int CODEC_FLAG_GRAY
     156    int CODEC_FLAG_EMU_EDGE
     157    int CODEC_FLAG_PSNR
     158    int CODEC_FLAG_TRUNCATED
     159    int CODEC_FLAG_NORMALIZE_AQP
     160    int CODEC_FLAG_INTERLACED_DCT
     161    int CODEC_FLAG_GLOBAL_HEADER
     162
    76163    int CODEC_FLAG2_FAST
     164
    77165    int CODEC_CAP_DRAW_HORIZ_BAND
    78166    int CODEC_CAP_DR1
    79167    int CODEC_CAP_TRUNCATED
     
    94182    int CODEC_CAP_LOSSLESS
    95183
    96184    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
     185        uint8_t     **data
     186        int         *linesize
     187        int         width
     188        int         height
     189        int         format
     190        int         key_frame
     191        int64_t     pts
     192        int         coded_picture_number
     193        int         display_picture_number
     194        int         quality
     195        void        *opaque
    108196        AVPictureType pict_type
    109197    ctypedef struct AVCodec:
    110         int capabilities
    111         const char *name
    112         const char *long_name
     198        int         capabilities
     199        const char  *name
     200        const char  *long_name
    113201    ctypedef struct AVDictionary:
    114202        pass
     203    int AV_PKT_FLAG_KEY
     204    int AV_PKT_FLAG_CORRUPT
    115205    ctypedef struct AVPacket:
     206        int64_t pts
     207        int64_t dts
    116208        uint8_t *data
    117         int      size
     209        int     size
     210        int     stream_index
     211        int     flags
     212        AVPacketSideData *side_data
     213        int     side_data_elems
     214        int64_t duration
     215        int64_t pos
    118216
    119217    ctypedef struct AVRational:
    120218        int num
     
    136234        int delay
    137235        AVRational framerate
    138236        AVRational time_base
     237        unsigned int codec_tag
    139238
    140239    ctypedef struct AVFormatContext:
    141         pass
     240        const AVClass   *av_class
     241        AVInputFormat   *iformat
     242        AVOutputFormat  *oformat
     243        void            *priv_data
     244        AVIOContext     *pb
     245        int             ctx_flags
     246        unsigned int    nb_streams
     247        AVStream        **streams
     248        char            filename[1024]
     249        int64_t         start_time
     250        int64_t         duration
     251        int             bit_rate
     252        unsigned int    packet_size
     253        int             max_delay
     254        int             flags
     255        unsigned int    probesize
     256        int             max_analyze_duration
     257        const uint8_t   *key
     258        int             keylen
     259        unsigned int    nb_programs
     260        AVProgram       **programs
     261        AVCodecID       video_codec_id
     262        AVCodecID       audio_codec_id
     263        AVCodecID       subtitle_codec_id
     264        unsigned int    max_index_size
     265        unsigned int    max_picture_buffer
     266        unsigned int    nb_chapters
     267        AVChapter       **chapters
     268        AVDictionary    *metadata
     269        int64_t         start_time_realtime
     270        int             fps_probe_size
     271        int             error_recognition
     272        AVIOInterruptCB interrupt_callback
     273        int             debug
     274        int64_t         max_interleave_delta
     275        int             strict_std_compliance
     276        int             event_flags
     277        int             max_ts_probe
     278        int             avoid_negative_ts
     279        AVFormatInternal *internal
     280        void            *opaque
     281        int             (*io_open)(AVFormatContext *s, AVIOContext **pb, const char *url, int flags, AVDictionary **options)
     282        void            (*io_close)(AVFormatContext *s, AVIOContext *pb)
     283        char            *protocol_blacklist
     284        char            *protocol_whitelist
    142285
     286    ctypedef int AVMediaType
     287    ctypedef int AVFieldOrder
     288    ctypedef int AVColorRange
     289    ctypedef int AVColorPrimaries
     290    ctypedef int AVColorTransferCharacteristic
     291    ctypedef int AVColorSpace
     292    ctypedef int AVChromaLocation
     293    ctypedef struct AVCodecParameters:
     294        AVMediaType     codec_type
     295        AVCodecID       codec_id
     296        uint32_t        codec_tag
     297        uint8_t         *extradata
     298        int             extradata_size
     299        int             format
     300        int64_t         bit_rate
     301        int             bits_per_coded_sample
     302        int             bits_per_raw_sample
     303        int             profile
     304        int             level
     305        int             width
     306        int             height
     307        AVRational      sample_aspect_ratio
     308        AVFieldOrder    field_order
     309        AVColorRange    color_range
     310        AVColorPrimaries    color_primaries
     311        AVColorTransferCharacteristic color_trc
     312        AVColorSpace        color_space
     313        AVChromaLocation    chroma_location
     314        int             video_delay
     315        uint64_t        channel_layout
     316        int             channels
     317        int             sample_rate
     318        int             block_align
     319        int             frame_size
     320        int             initial_padding
     321        int             trailing_padding
     322        int             seek_preroll
     323
    143324    AVCodecID AV_CODEC_ID_H264
    144325    AVCodecID AV_CODEC_ID_H265
    145326    AVCodecID AV_CODEC_ID_VP8
     
    162343    void av_init_packet(AVPacket *pkt) nogil
    163344    void av_packet_unref(AVPacket *pkt) nogil
    164345
     346ctypedef int AVOptionType
    165347
     348cdef extern from "libavutil/opt.h":
     349    AVOptionType AV_OPT_TYPE_FLAGS
     350    AVOptionType AV_OPT_TYPE_INT
     351    AVOptionType AV_OPT_TYPE_INT64
     352    AVOptionType AV_OPT_TYPE_DOUBLE
     353    AVOptionType AV_OPT_TYPE_FLOAT
     354    AVOptionType AV_OPT_TYPE_STRING
     355    AVOptionType AV_OPT_TYPE_RATIONAL
     356    AVOptionType AV_OPT_TYPE_BINARY         #offset must point to a pointer immediately followed by an int for the length
     357    AVOptionType AV_OPT_TYPE_DICT
     358    AVOptionType AV_OPT_TYPE_CONST
     359    AVOptionType AV_OPT_TYPE_IMAGE_SIZE
     360    AVOptionType AV_OPT_TYPE_PIXEL_FMT
     361    AVOptionType AV_OPT_TYPE_SAMPLE_FMT
     362    AVOptionType AV_OPT_TYPE_VIDEO_RATE
     363    AVOptionType AV_OPT_TYPE_DURATION
     364    AVOptionType AV_OPT_TYPE_COLOR
     365    AVOptionType AV_OPT_TYPE_CHANNEL_LAYOUT
     366    AVOptionType AV_OPT_TYPE_BOOL
     367
     368    int AV_OPT_SEARCH_CHILDREN
     369    int AV_OPT_SEARCH_FAKE_OBJ
     370
     371    ctypedef struct AVOption:
     372        const char *name        #short English help text
     373        const char *help
     374        int offset              #The offset relative to the context structure where the option value is stored. It should be 0 for named constants.
     375        AVOptionType type
     376        int flags
     377        const char *unit
     378
     379    const AVOption* av_opt_next(void *obj, const AVOption *prev)       
     380    void *av_opt_child_next(void *obj, void *prev)
     381    int av_opt_set_int(void *obj, const char *name, int64_t val, int search_flags)
     382    int av_opt_get_int(void *obj, const char *name, int search_flags, int64_t *out_val)
     383
     384
     385cdef extern from "libavutil/log.h":
     386    ctypedef struct AVClass:
     387        const char  *class_name                 #The name of the class; usually it is the same name as the context structure type to which the AVClass is associated.
     388        const char  *(*item_name)(void *ctx)    #A pointer to a function which returns the name of a context instance ctx associated with the class.
     389        AVOption    *option                     #a pointer to the first option specified in the class if any or NULL
     390        int         version                     #LIBAVUTIL_VERSION with which this structure was created
     391        int         log_level_offset_offset     #Offset in the structure where log_level_offset is stored
     392        int         parent_log_context_offset   #Offset in the structure where a pointer to the parent context for logging is stored
     393        void        *(*child_next)(void *obj, void *prev)  #Return next AVOptions-enabled child or NULL
     394        AVClass     *(*child_class_next)(const AVClass *prev) #Return an AVClass corresponding to the next potential AVOptions-enabled child.
     395        #AVClassCategory category                #Category used for visualization (like color) This is only set if the category is equal for all objects using this class.
     396        #AVClassCategory (*get_category)(void *ctx)
     397
     398
     399cdef extern from "libavformat/avformat.h":
     400    int AVFMTCTX_NOHEADER           #signal that no header is present
     401
     402    int AVFMT_FLAG_GENPTS           #Generate missing pts even if it requires parsing future frames
     403    int AVFMT_FLAG_IGNIDX           #Ignore index
     404    int AVFMT_FLAG_NONBLOCK         #Do not block when reading packets from input
     405    int AVFMT_FLAG_IGNDTS           #Ignore DTS on frames that contain both DTS & PTS
     406    int AVFMT_FLAG_NOFILLIN         #Do not infer any values from other values, just return what is stored in the container
     407    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
     408    int AVFMT_FLAG_NOBUFFER         #Do not buffer frames when possible
     409    int AVFMT_FLAG_CUSTOM_IO        #The caller has supplied a custom AVIOContext, don't avio_close() it
     410    int AVFMT_FLAG_DISCARD_CORRUPT  #Discard frames marked corrupted
     411    int AVFMT_FLAG_FLUSH_PACKETS    #Flush the AVIOContext every packet
     412    int AVFMT_FLAG_BITEXACT
     413    int AVFMT_FLAG_MP4A_LATM        #Enable RTP MP4A-LATM payload
     414    int AVFMT_FLAG_SORT_DTS         #try to interleave outputted packets by dts (using this flag can slow demuxing down)
     415    int AVFMT_FLAG_PRIV_OPT         #Enable use of private options by delaying codec open (this could be made default once all code is converted)
     416    int AVFMT_FLAG_KEEP_SIDE_DATA   #Don't merge side data but keep it separate.
     417    int AVFMT_FLAG_FAST_SEEK        #Enable fast, but inaccurate seeks for some formats
     418
     419    int AVFMT_NOFILE                #Demuxer will use avio_open, no opened file should be provided by the caller
     420    int AVFMT_NEEDNUMBER            #Needs '%d' in filename
     421    int AVFMT_SHOW_IDS              #Show format stream IDs numbers
     422    int AVFMT_RAWPICTURE            #Format wants AVPicture structure for raw picture data. @deprecated Not used anymore
     423    int AVFMT_GLOBALHEADER          #Format wants global header
     424    int AVFMT_NOTIMESTAMPS          #Format does not need / have any timestamps
     425    int AVFMT_GENERIC_INDEX         #Use generic index building code
     426    int AVFMT_TS_DISCONT            #Format allows timestamp discontinuities. Note, muxers always require valid (monotone) timestamps
     427    int AVFMT_VARIABLE_FPS          #Format allows variable fps
     428    int AVFMT_NODIMENSIONS          #Format does not need width/height
     429    int AVFMT_NOSTREAMS             #Format does not require any streams
     430    int AVFMT_NOBINSEARCH           #Format does not allow to fall back on binary search via read_timestamp
     431    int AVFMT_NOGENSEARCH           #Format does not allow to fall back on generic search
     432    int AVFMT_NO_BYTE_SEEK          #Format does not allow seeking by bytes
     433    int AVFMT_ALLOW_FLUSH           #Format allows flushing. If not set, the muxer will not receive a NULL packet in the write_packet function
     434    int AVFMT_TS_NONSTRICT          #Format does not require strictly increasing timestamps, but they must still be monotonic
     435    int AVFMT_TS_NEGATIVE           #Format allows muxing negative timestamps.
     436    int AVFMT_SEEK_TO_PTS           #Seeking is based on PTS
     437
     438    ctypedef int AVStreamParseType
     439    ctypedef struct AVInputFormat:
     440        pass
     441    ctypedef struct AVProgram:
     442        pass
     443    ctypedef struct AVChapter:
     444        pass
     445    ctypedef struct AVFormatInternal:
     446        pass
     447    ctypedef struct AVPacketSideData:
     448        pass
     449    ctypedef struct AVStream:
     450        int         index           #stream index in AVFormatContext
     451        int         id
     452        AVCodecContext *codec
     453        AVRational  time_base
     454        int64_t     start_time
     455        int64_t     duration
     456        int64_t     nb_frames       #number of frames in this stream if known or 0
     457        int         disposition
     458        #AVDiscard   discard         #Selects which packets can be discarded at will and do not need to be demuxed.
     459        AVRational  sample_aspect_ratio
     460        AVDictionary *metadata
     461        AVRational  avg_frame_rate
     462        AVPacket    attached_pic
     463        AVPacketSideData *side_data
     464        int         nb_side_data
     465        int         event_flags
     466        int         pts_wrap_bits   #number of bits in pts (used for wrapping control)
     467        int64_t     first_dts
     468        int64_t     cur_dts
     469        int64_t     last_IP_pts
     470        int         last_IP_duration
     471        int         probe_packets
     472        int         codec_info_nb_frames
     473        AVStreamParseType need_parsing
     474        #AVPacketList *last_in_packet_buffer
     475        #AVProbeData probe_data
     476        int         stream_identifier
     477        char        *recommended_encoder_configuration
     478        AVCodecParameters *codecpar
     479
     480    ctypedef struct AVOutputFormat:
     481        const char  *name
     482        const char  *long_name
     483        const char  *mime_type
     484        const char  *extensions
     485        AVCodecID   audio_codec
     486        AVCodecID   video_codec
     487        AVCodecID   subtitle_codec
     488        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...
     489        #AVCodecTag *const *     codec_tag
     490        int     priv_data_size
     491        int(*write_header)(AVFormatContext *)
     492        int(*write_packet)(AVFormatContext *, AVPacket *pkt)
     493        int(*write_trailer )(AVFormatContext *)
     494        int(*interleave_packet)(AVFormatContext *, AVPacket *out, AVPacket *input, int flush)
     495        int(*query_codec)(AVCodecID id, int std_compliance)
     496        void(*get_output_timestamp )(AVFormatContext *s, int stream, int64_t *dts, int64_t *wall)
     497        int(*control_message )(AVFormatContext *s, int type, void *data, size_t data_size)
     498        int(*write_uncoded_frame )(AVFormatContext *, int stream_index, AVFrame **frame, unsigned flags)
     499        #int(*get_device_list )(AVFormatContext *s, struct AVDeviceInfoList *device_list)
     500        #int(*create_device_capabilities )(AVFormatContext *s, AVDeviceCapabilitiesQuery *caps)
     501        #int(*free_device_capabilities )(AVFormatContext *s, AVDeviceCapabilitiesQuery *caps)
     502        AVCodecID   data_codec
     503        int(*init)(AVFormatContext *)
     504        void(*deinit)(AVFormatContext *)
     505        int(*check_bitstream )(AVFormatContext *, const AVPacket *pkt)
     506
     507    void av_register_all()
     508    AVOutputFormat *av_oformat_next (const AVOutputFormat *f)
     509    int avformat_alloc_output_context2(AVFormatContext **ctx, AVOutputFormat *oformat, const char *format_name, const char *filename)
     510    void avformat_free_context(AVFormatContext *s)
     511
     512    int avcodec_parameters_from_context(AVCodecParameters *par, const AVCodecContext *codec)
     513    int avcodec_parameters_to_context(AVCodecContext *codec, const AVCodecParameters *par)
     514    AVStream *avformat_new_stream(AVFormatContext *s, const AVCodec *c)
     515    int avformat_write_header(AVFormatContext *s, AVDictionary **options)
     516    int av_write_trailer(AVFormatContext *s)
     517    int av_interleaved_write_frame(AVFormatContext *s, AVPacket *pkt)
     518    int av_write_frame(AVFormatContext *s, AVPacket *pkt)
     519    #void add_stream(OutputStream *ost, AVFormatContext *oc, AVCodec **codec, AVCodecID codec_id)
     520
     521AV_OPT_TYPES = {
     522                AV_OPT_TYPE_FLAGS       : "FLAGS",
     523                AV_OPT_TYPE_INT         : "INT",
     524                AV_OPT_TYPE_INT64       : "INT64",
     525                AV_OPT_TYPE_DOUBLE      : "DOUBLE",
     526                AV_OPT_TYPE_FLOAT       : "FLOAT",
     527                AV_OPT_TYPE_STRING      : "STRING",
     528                AV_OPT_TYPE_RATIONAL    : "RATIONAL",
     529                AV_OPT_TYPE_BINARY      : "BINARY",
     530                AV_OPT_TYPE_DICT        : "DICT",
     531                AV_OPT_TYPE_CONST       : "CONST",
     532                AV_OPT_TYPE_IMAGE_SIZE  : "IMAGE_SIZE",
     533                AV_OPT_TYPE_PIXEL_FMT   : "PIXEL_FMT",
     534                AV_OPT_TYPE_SAMPLE_FMT  : "SAMPLE_FMT",
     535                AV_OPT_TYPE_VIDEO_RATE  : "VIDEO_RATE",
     536                AV_OPT_TYPE_DURATION    : "DURATION",
     537                AV_OPT_TYPE_COLOR       : "COLOR",
     538                AV_OPT_TYPE_CHANNEL_LAYOUT : "CHANNEL_LAYOUT",
     539                AV_OPT_TYPE_BOOL        : "BOOL",
     540                }
     541
     542
     543PKT_FLAGS = {
     544             AV_PKT_FLAG_KEY        : "KEY",
     545             AV_PKT_FLAG_CORRUPT    : "CORRUPT",
     546             }
     547
     548AVFMTCTX = {
     549            AVFMTCTX_NOHEADER       : "NOHEADER",
     550            }
     551
     552FMT_FLAGS = {
     553             AVFMT_FLAG_GENPTS          : "GENPTS",
     554             AVFMT_FLAG_IGNIDX          : "IGNIDX",
     555             AVFMT_FLAG_NONBLOCK        : "NONBLOCK",
     556             AVFMT_FLAG_IGNDTS          : "IGNDTS",
     557             AVFMT_FLAG_NOFILLIN        : "NOFILLIN",
     558             AVFMT_FLAG_NOPARSE         : "NOPARSE",
     559             AVFMT_FLAG_NOBUFFER        : "NOBUFFER",
     560             AVFMT_FLAG_CUSTOM_IO       : "CUSTOM_IO",
     561             AVFMT_FLAG_DISCARD_CORRUPT : "DISCARD_CORRUPT",
     562             AVFMT_FLAG_FLUSH_PACKETS   : "FLUSH_PACKETS",
     563             AVFMT_FLAG_BITEXACT        : "BITEXACT",
     564             AVFMT_FLAG_MP4A_LATM       : "MP4A_LATM",
     565             AVFMT_FLAG_SORT_DTS        : "SORT_DTS",
     566             AVFMT_FLAG_PRIV_OPT        : "PRIV_OPT",
     567             AVFMT_FLAG_KEEP_SIDE_DATA  : "KEEP_SIDE_DATA",
     568             AVFMT_FLAG_FAST_SEEK       : "FAST_SEEK",
     569             }
     570
     571AVFMT = {
     572         AVFMT_NOFILE           : "NOFILE",
     573         AVFMT_NEEDNUMBER       : "NEEDNUMBER",
     574         AVFMT_SHOW_IDS         : "SHOW_IDS",
     575         AVFMT_RAWPICTURE       : "RAWPICTURE",
     576         AVFMT_GLOBALHEADER     : "GLOBALHEADER",
     577         AVFMT_NOTIMESTAMPS     : "NOTIMESTAMPS",
     578         AVFMT_GENERIC_INDEX    : "GENERIC_INDEX",
     579         AVFMT_TS_DISCONT       : "TS_DISCONT",
     580         AVFMT_VARIABLE_FPS     : "VARIABLE_FPS",
     581         AVFMT_NODIMENSIONS     : "NODIMENSIONS",
     582         AVFMT_NOSTREAMS        : "NOSTREAMS",
     583         AVFMT_NOBINSEARCH      : "NOBINSEARCH",
     584         AVFMT_NOGENSEARCH      : "NOGENSEARCH",
     585         AVFMT_NO_BYTE_SEEK     : "NO_BYTE_SEEK",
     586         AVFMT_ALLOW_FLUSH      : "ALLOW_FLUSH",
     587         AVFMT_TS_NONSTRICT     : "TS_NONSTRICT",
     588         AVFMT_TS_NEGATIVE      : "TS_NEGATIVE",
     589         AVFMT_SEEK_TO_PTS      : "SEEK_TO_PTS",
     590         }
     591
     592
    166593CAPS = {
    167594        CODEC_CAP_DRAW_HORIZ_BAND       : "DRAW_HORIZ_BAND",
    168595        CODEC_CAP_DR1                   : "DR1",
     
    218645log("AV_PIX_FMT:")
    219646print_nested_dict(ENUM_TO_FORMAT, print_fn=log.debug)
    220647
     648def flagscsv(flag_dict, value=0):
     649    return csv([v for k,v in flag_dict.items() if k&value])
     650
     651
     652def get_muxer_formats():
     653    av_register_all()
     654    cdef AVOutputFormat *fmt = NULL
     655    formats = {}
     656    while True:
     657        fmt = av_oformat_next(fmt)
     658        if fmt==NULL:
     659            break
     660        name = fmt.name
     661        long_name = fmt.long_name
     662        formats[name] = long_name
     663    return formats
     664log("AV Output Formats:")
     665print_nested_dict(get_muxer_formats(), print_fn=log.debug)
     666
     667cdef AVOutputFormat* get_av_output_format(name):
     668    cdef AVOutputFormat *fmt = NULL
     669    while True:
     670        fmt = av_oformat_next(fmt)
     671        if fmt==NULL:
     672            break
     673        if name==fmt.name:
     674            return fmt
     675    return NULL
     676
     677
    221678def get_version():
    222679    return (LIBAVCODEC_VERSION_MAJOR, LIBAVCODEC_VERSION_MINOR, LIBAVCODEC_VERSION_MICRO)
    223680
     
    231688#    CODECS.append("vp9")
    232689#if avcodec_find_encoder(AV_CODEC_ID_H265)!=NULL:
    233690#    CODECS.append("h265")
    234 #if avcodec_find_encoder(AV_CODEC_ID_MPEG4)!=NULL:
    235 #    CODECS.append("mpeg4")
     691if avcodec_find_encoder(AV_CODEC_ID_MPEG4)!=NULL:
     692    CODECS.append("mpeg4")
    236693log("enc_ffmpeg CODECS=%s", csv(CODECS))
    237694
    238695cdef av_error_str(int errnum):
     
    267724    return  {
    268725             "version"      : get_version(),
    269726             "encodings"    : get_encodings(),
     727             "muxers"       : get_muxer_formats(),
    270728             "buffer_api"   : get_buffer_api_version(),
    271729             "formats"      : f,
    272730             "generation"   : generation.get(),
     
    285743    return ["YUV420P"]
    286744
    287745
     746GEN_TO_ENCODER = weakref.WeakValueDictionary()
     747
     748
     749cdef list_options(void *obj, const AVClass *av_class):
     750    if av_class==NULL:
     751        return
     752    cdef const AVOption *option = <const AVOption*> av_class.option
     753    options = []
     754    while option!=NULL:
     755        oname = option.name
     756        options.append(oname)
     757        option = av_opt_next(obj, option)
     758    log("%s options: %s", av_class.class_name, csv(options))
     759    cdef void *child = NULL
     760    cdef const AVClass *child_class = NULL
     761    while True:
     762        child = av_opt_child_next(obj, child)
     763        if child==NULL:
     764            return
     765        child_class = (<AVClass**> child)[0]
     766        list_options(child, child_class)
     767
     768
     769cdef int write_packet(void *opaque, uint8_t *buf, int buf_size):
     770    global GEN_TO_ENCODER
     771    encoder = GEN_TO_ENCODER.get(<unsigned long> opaque)
     772    log.warn("write_packet(%#x, %#x, %#x) encoder=%s", <unsigned long> opaque, <unsigned long> buf, buf_size, type(encoder))
     773    if not encoder:
     774        log.error("Error: write_packet called for encoder %i!", <unsigned long> opaque)
     775        return -1
     776    return encoder.write_packet(<unsigned long> buf, buf_size)
     777
     778cdef int64_t seek(void *opaque, int64_t offset, int whence):
     779    global GEN_TO_ENCODER
     780    encoder = GEN_TO_ENCODER.get(<unsigned long> opaque)
     781    if not encoder:
     782        log.error("Error: seek called for encoder %i!", <unsigned long> opaque)
     783        return -1
     784    return encoder.seek(offset, whence)
     785
     786
    288787MAX_WIDTH, MAX_HEIGHT = 4096, 4096
    289788def get_spec(encoding, colorspace):
    290789    assert encoding in get_encodings(), "invalid encoding: %s (must be one of %s" % (encoding, get_encodings())
     
    300799        This wraps the AVCodecContext and its configuration,
    301800    """
    302801    cdef AVCodec *codec
     802    cdef AVStream *stream
     803    cdef AVFormatContext *format_ctx
     804    cdef unsigned char *buffer
     805    cdef object buffers
     806    cdef int64_t buf_len
     807    cdef int64_t offset
    303808    cdef AVCodecContext *codec_ctx
    304809    cdef AVPixelFormat pix_fmt
    305810    cdef object src_format
     
    309814    cdef unsigned int width
    310815    cdef unsigned int height
    311816    cdef object encoding
     817    cdef object muxer_format
    312818    cdef object file
    313819
    314820    cdef object __weakref__
    315821
    316822    def init_context(self, unsigned int width, unsigned int height, src_format, dst_formats, encoding, int quality, int speed, scaling, options):    #@DuplicatedSignature
     823        cdef int r
    317824        global CODECS, generation
    318825        assert encoding in CODECS
    319826        assert src_format in get_input_colorspaces(encoding), "invalid colorspace: %s" % src_format
     
    324831        self.pix_fmt = FORMAT_TO_ENUM.get(src_format, AV_PIX_FMT_NONE)
    325832        if self.pix_fmt==AV_PIX_FMT_NONE:
    326833            raise Exception("invalid pixel format: %s", src_format)
     834        self.buffers = []
    327835
    328836        avcodec_register_all()
    329837        cdef AVCodecID CodecID
     
    342850        self.codec = avcodec_find_encoder(CodecID)
    343851        if self.codec==NULL:
    344852            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)))
     853        log("%s: \"%s\", codec flags: %s", self.codec.name, self.codec.long_name, flagscsv(CAPS, self.codec.capabilities))
    346854
    347         #from here on, we have to call clean_encoder():
     855        #TODO: the muxer should be configurable
     856        self.muxer_format = "mp4"   #"mov", "f4v"
     857        cdef int b_frames = 0   #int(options.get("b-frames"))
     858        try:
     859            self.init_encoder(b_frames)
     860        except Exception as e:
     861            log("init_encoder(%i) failed", b_frames, exc_info=True)
     862            self.clean()
     863            raise
     864        else:
     865            log("enc_ffmpeg.Encoder.init_context(%s, %s, %s) self=%s", self.width, self.height, self.src_format, self.get_info())
     866
     867    def init_encoder(self, int b_frames):
     868        global GEN_TO_ENCODER
     869        cdef AVOutputFormat *oformat = get_av_output_format(self.muxer_format)
     870        if oformat==NULL:
     871            raise Exception("libavformat does not support %s" % self.muxer_format)
     872        log("init_encoder() AVOutputFormat(%s)=%#x, flags=%s", self.muxer_format, <unsigned long> oformat, flagscsv(AVFMT, oformat.flags))
     873        if oformat.flags & AVFMT_ALLOW_FLUSH==0:
     874            raise Exception("AVOutputFormat(%s) does not support flushing!" % self.muxer_format)
     875        r = avformat_alloc_output_context2(&self.format_ctx, oformat, self.muxer_format, NULL)
     876        if r!=0:
     877            msg = av_error_str(r)
     878            raise Exception("libavformat cannot allocate context: %s" % msg)
     879        log("init_encoder() avformat_alloc_output_context2 returned %i, format context=%#x, flags=%s, ctx_flags=%s", r, <unsigned long> self.format_ctx,
     880            flagscsv(FMT_FLAGS, self.format_ctx.flags), flagscsv(AVFMTCTX, self.format_ctx.ctx_flags))
     881        list_options(self.format_ctx, self.format_ctx.av_class)
     882
     883        cdef int64_t v = 0
     884        r = av_opt_get_int(self.format_ctx, "movflags", AV_OPT_SEARCH_CHILDREN, &v)
     885        if r==0:
     886            log("movflags=%#x", v)
     887            FF_MOV_FLAG_FRAGMENT = 1<<1
     888            v |= FF_MOV_FLAG_FRAGMENT
     889            r = av_opt_set_int(self.format_ctx, "movflags", v, AV_OPT_SEARCH_CHILDREN)
     890            if r!=0:
     891                log.error("Error: failed to set movflags")
     892                log.error(" %s", av_error_str(r))
     893
     894        cdef unsigned long gen = generation.increase()
     895        GEN_TO_ENCODER[gen] = self
     896        if SAVE_TO_FILE:
     897            filename = SAVE_TO_FILE+"ffmpeg-"+self.encoding+"-"+str(gen)+".%s" % self.muxer_format
     898            r = avio_open(&self.format_ctx.pb, filename, AVIO_FLAG_WRITE)
     899            if r!=0:
     900                msg = av_error_str(r)
     901                raise Exception("libavformat cannot open file '%s': %s" % (filename, msg))
     902            log.info("init_encoder() saving %s stream to %s", self.encoding, filename)
     903        else:
     904            self.buf_len = 64*1024
     905            self.buffer = <unsigned char*> av_malloc(self.buf_len)
     906            if self.buffer==NULL:
     907                raise Exception("failed to allocate %iKB of memory" % (self.buf_len//1024))
     908            self.format_ctx.pb = avio_alloc_context(self.buffer, self.buf_len, 1, <void *> gen, NULL, write_packet, NULL)
     909            if self.format_ctx.pb==NULL:
     910                raise Exception("libavformat failed to allocate io context")
     911            #self.format_ctx.flags |= AVFMT_FLAG_CUSTOM_IO
     912            log.info("init_encoder() saving %s stream to bitstream buffer %#x", self.encoding, <unsigned long> self.buffer)
     913
     914        self.stream = avformat_new_stream(self.format_ctx, NULL)
     915        log("init_encoder() avformat_new_stream=%#x", <unsigned long> self.stream)
     916        self.stream.id = 0
     917        self.stream.time_base.num = 1
     918        self.stream.time_base.den = 25
     919
    348920        self.codec_ctx = avcodec_alloc_context3(self.codec)
    349921        if self.codec_ctx==NULL:
    350             self.clean_encoder()
    351922            raise Exception("failed to allocate codec context!")
    352923
    353         cdef int b_frames = int(options.get("b-frames"))
     924        #r = avcodec_parameters_to_context(self.codec_ctx, self.stream.codecpar)
     925        #if r<0:
     926        #    raise Exception("could not copy context parameters %#x: %s" % (<unsigned long> self.stream.codecpar, av_error_str(r)))
    354927        #we need a framerate.. make one up:
    355928        self.codec_ctx.framerate.num = 1
    356929        self.codec_ctx.framerate.den = 25
     
    361934        self.codec_ctx.has_b_frames = b_frames
    362935        self.codec_ctx.delay = 0
    363936        self.codec_ctx.gop_size = 1
    364         self.codec_ctx.width = width
    365         self.codec_ctx.height = height
     937        self.codec_ctx.width = self.width
     938        self.codec_ctx.height = self.height
    366939        self.codec_ctx.pix_fmt = self.pix_fmt
    367940        self.codec_ctx.thread_safe_callbacks = 1
    368941        self.codec_ctx.thread_type = 2      #FF_THREAD_SLICE: allow more than one thread per frame
    369942        self.codec_ctx.thread_count = 0     #auto
     943        self.codec_ctx.flags |= CODEC_FLAG_GLOBAL_HEADER
    370944        self.codec_ctx.flags2 |= CODEC_FLAG2_FAST   #may cause "no deblock across slices" - which should be fine
    371945        #av_opt_set(c->priv_data, "preset", "slow", 0)
    372         cdef int r = avcodec_open2(self.codec_ctx, self.codec, NULL)
     946
     947        r = avcodec_open2(self.codec_ctx, self.codec, NULL)
     948        if r!=0:
     949            raise Exception("could not open %s encoder context: %s" % (self.encoding, av_error_str(r)))
     950
     951        r = avcodec_parameters_from_context(self.stream.codecpar, self.codec_ctx)
    373952        if r<0:
    374             self.clean_encoder()
    375             raise Exception("could not open %s encoder context: %s" % (self.encoding, av_error_str(r)))
     953            raise Exception("could not copy context parameters %#x: %s" % (<unsigned long> self.stream.codecpar, av_error_str(r)))
     954
    376955        self.av_frame = av_frame_alloc()
    377956        if self.av_frame==NULL:
    378             self.clean_encoder()
    379957            raise Exception("could not allocate an AVFrame for encoding")
    380958        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)
    387959
     960        log("init_encoder() writing %s header", self.muxer_format)
     961        r = avformat_write_header(self.format_ctx, NULL)
     962        if r!=0:
     963            msg = av_error_str(r)
     964            raise Exception("libavformat failed to write header: %s" % msg)
     965
    388966    def clean(self):
    389967        self.clean_encoder()
    390968        self.codec = NULL
     
    395973        self.width = 0
    396974        self.height = 0
    397975        self.encoding = ""
    398         f = self.file
    399         if f:
    400             self.file = None
    401             f.close()
     976        self.buffers = []
    402977
    403 
    404978    def clean_encoder(self):
    405         cdef int r, i
     979        cdef int r
    406980        log("%s.clean_encoder()", self)
    407981
    408982        if self.av_frame!=NULL:
     
    410984            av_frame_free(&self.av_frame)
    411985            #redundant: self.frame = NULL
    412986
     987        if self.format_ctx!=NULL:
     988            if self.frames>0:
     989                log("clean_encoder() writing trailer to stream")
     990                av_write_trailer(self.format_ctx)
     991
     992                if SAVE_TO_FILE:
     993                    r = avio_close(self.format_ctx.pb)
     994                    if r<0:
     995                        log.error("Error closing IO context: %s", av_error_str(r))
     996                else:
     997                    if self.format_ctx.pb!=NULL:
     998                        av_free(self.format_ctx.pb)
     999                        self.format_ctx.pb = NULL
     1000
     1001            log("clean_encoder() freeing av format context %#x", <unsigned long> self.format_ctx)
     1002            avformat_free_context(self.format_ctx)
     1003            self.format_ctx = NULL
     1004
     1005            log("clean_encoder() freeing bitstream buffer %#x", <unsigned long> self.buffer)
     1006            if self.buffer!=NULL:
     1007                av_free(self.buffer)
     1008                self.buffer = NULL
     1009
    4131010        cdef unsigned long ctx_key          #@DuplicatedSignature
    4141011        log("clean_encoder() freeing AVCodecContext: %#x", <unsigned long> self.codec_ctx)
    4151012        if self.codec_ctx!=NULL:
     
    4191016                log.error(" %s", av_error_str(r))
    4201017            av_free(self.codec_ctx)
    4211018            self.codec_ctx = NULL
     1019
     1020        if self.buffers:
     1021            import time
     1022            filename = SAVE_TO_FILE+"ffmpeg-"+self.encoding+"-"+str(int(time.time()))+".%s" % self.muxer_format
     1023            log("clean_encoder() saving %i buffers", len(self.buffers))
     1024            with open(filename, 'wb') as f:
     1025                for b in self.buffers:
     1026                    f.write(b)
     1027
    4221028        log("clean_encoder() done")
    4231029
    4241030    def __repr__(self):                      #@DuplicatedSignature
     
    4301036        info = {
    4311037                "version"   : get_version(),
    4321038                "encoding"  : self.encoding,
     1039                "muxer"     : self.muxer_format,
    4331040                "formats"   : get_input_colorspaces(self.encoding),
    4341041                "type"      : self.get_type(),
    4351042                "frames"    : self.frames,
     
    5021109            istrides = image.get_rowstride()
    5031110            assert len(pixels)==3, "image pixels does not have 3 planes! (found %s)" % len(pixels)
    5041111            assert len(istrides)==3, "image strides does not have 3 values! (found %s)" % len(istrides)
    505    
     1112
    5061113            #populate the avframe:
    5071114            for i in range(4):
    5081115                if i<3:
     
    5181125            self.av_frame.pts = self.frames+1
    5191126            self.av_frame.coded_picture_number = self.frames+1
    5201127            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
     1128            #if self.frames==0:
     1129            #    self.av_frame.pict_type = AV_PICTURE_TYPE_I
     1130            #else:
     1131            #    self.av_frame.pict_type = AV_PICTURE_TYPE_P
    5251132            #self.av_frame.quality = 1
    5261133            frame = self.av_frame
    5271134        else:
     
    5601167                raise Exception(av_error_str(ret))
    5611168            if ret>0:
    5621169                free(avpkt.data)
    563                 self.log_error(image, ret, options, "no stream")
     1170                self.log_av_error(image, ret, options, "no stream")
    5641171                raise Exception("no stream")
    565             log("avcodec_receive_packet returned %#x bytes of data", avpkt.size)
     1172            log("avcodec_receive_packet returned %#x bytes of data, flags: %s", avpkt.size, flagscsv(PKT_FLAGS, avpkt.flags))
     1173            if avpkt.flags & AV_PKT_FLAG_CORRUPT:
     1174                free(avpkt.data)
     1175                self.log_error(image, "packet", options, "av packet is corrupt")
     1176                raise Exception("av packet is corrupt")
    5661177            packet_data = avpkt.data[:avpkt.size]
    5671178            bufs.append(packet_data)
    568             if self.file and packet_data:
    569                 self.file.write(packet_data)
    570                 self.file.flush()
     1179
     1180            if SAVE_TO_FILE or True:
     1181                avpkt.stream_index = self.stream.index
     1182                r = av_write_frame(self.format_ctx, &avpkt)
     1183                if ret<0:
     1184                    free(avpkt.data)
     1185                    self.log_av_error(image, ret, options)
     1186                    raise Exception(av_error_str(ret))
     1187                r = av_write_frame(self.format_ctx, NULL)
     1188                if ret<0:
     1189                    free(avpkt.data)
     1190                    self.log_av_error(image, ret, options)
     1191                    raise Exception(av_error_str(ret))
    5711192        av_packet_unref(&avpkt)
    5721193        free(avpkt.data)
    5731194        self.frames += 1
     
    5811202        self.clean()
    5821203        return v
    5831204
     1205    def write_packet(self, unsigned long buf, int buf_size):
     1206        log.warn("write_packet(%#x, %#x) buffer=%#x", <unsigned long> buf, buf_size, <unsigned long> self.buffer)
     1207        cdef uint8_t *cbuf = <uint8_t*> buf
     1208        #if buf!=self.buffer:
     1209        #    log.error("Error: write_packet buffer mismatch")
     1210        #    log.error(" expected %#x but received %#x", <unsigned long> self.buffer, <unsigned long> buf)
     1211        if self.offset+buf_size>self.buf_len:
     1212            log.error("Error: writing packet would overflow the buffer")
     1213            log.error(" current offset=%#x, data size=%#x, buffer size=%#x", self.offset, buf_size, self.buf_len)
     1214            return -1
     1215        memcpy(self.buffer + self.offset, cbuf, buf_size)
     1216        self.offset += buf_size
     1217        log("write_packet(%#x, %#x) new offset=%#x", <unsigned long> buf, buf_size, self.offset)
     1218        buffer = cbuf[:buf_size]
     1219        self.buffers.append(buffer)
     1220        return buf_size
    5841221
     1222    def seek(self, int64_t offset, int whence):
     1223        global SEEKS
     1224        if whence==SEEK_SET:
     1225            if offset<0:
     1226                log.warn("Warning: invalid SEEK_SET offset: %i", offset)
     1227                offset = 0
     1228            elif offset>=self.buf_len:
     1229                log.warn("Warning: invalid SEEK_SET offset: %i", offset)
     1230                return -1
     1231            self.offset = offset
     1232        elif whence==SEEK_CUR:
     1233            if self.offset+offset<0:
     1234                log.warn("Warning: invalid SEEK_CUR %i+%i clipped to 0", self.offset, offset)
     1235                self.offset = 0
     1236            elif self.offset+offset>=self.buf_len:
     1237                log.warn("Warning: invalid SEEK_CUR %i+%i clipped to %i", self.offset, offset, self.buf_len-1)
     1238                self.offset = self.buf_len-1
     1239            else:
     1240                self.offset += offset
     1241        elif whence==SEEK_END:
     1242            log.warn("Warning: SEEK_END not supported")
     1243            return -1
     1244        else:
     1245            log.error("Error: unknowm seek whence value %i", whence)
     1246            return -1           
     1247        log("seek(%i, %s)=%i", offset, SEEKS.get(whence, whence), self.offset)
     1248        return self.offset
     1249
     1250
    5851251def selftest(full=False):
    5861252    global CODECS
    5871253    from xpra.codecs.codec_checks import testencoder