xpra icon
Bug tracker and wiki

Ticket #1816: html5-mpeg1.patch

File html5-mpeg1.patch, 13.4 KB (added by Antoine Martin, 2 years ago)

mpeg1 encoder, decoder and stub html5 implementation

  • html5/js/Client.js

     
    5252        this.steal = true;
    5353        this.remote_logging = true;
    5454        this.enabled_encodings = [];
    55         this.supported_encodings = ["jpeg", "png", "rgb", "rgb32"];     //"h264", "vp8+webm", "h264+mp4", "mpeg4+mp4"];
     55        //this.supported_encodings = ["jpeg", "png", "rgb", "rgb32", "mpeg1", "mpeg2"]; //"h264", "vp8+webm", "h264+mp4", "mpeg4+mp4"];
     56        this.supported_encodings = ["mpeg1", "mpeg2"];  //"h264", "vp8+webm", "h264+mp4", "mpeg4+mp4"];
    5657        if (Utilities.canUseWebP()) {
    57                 this.supported_encodings.push("webp");
     58                //this.supported_encodings.push("webp");
    5859        }
    5960        this.debug_categories = [];
    6061        this.start_new_session = null;
     
    10471048                //video stuff:
    10481049                "encoding.video_scaling"        : true,
    10491050                "encoding.full_csc_modes"       : {
     1051                        "mpeg1"         : ["YUV420P"],
     1052                        "mpeg2"         : ["YUV420P"],
    10501053                        "h264"          : ["YUV420P"],
    10511054                        "mpeg4+mp4"     : ["YUV420P"],
    10521055                        "h264+mp4"      : ["YUV420P"],
  • html5/js/Window.js

     
    10671067        "vp9"     : "lavender",
    10681068        "mpeg4"   : "black",
    10691069        "scroll"  : "brown",
     1070        "mpeg1"   : "olive",
     1071        "mpeg2"   : "lime",
    10701072        }
    10711073
    10721074XpraWindow.prototype.do_paint = function paint(x, y, width, height, coding, img_data, packet_sequence, rowstride, options, decode_callback) {
     
    11601162                        }
    11611163                        j.src = "data:image/"+coding+";base64," + Utilities.ArrayBufferToBase64(img_data);
    11621164                }
     1165                else if (coding=="mpeg1" || coding=="mpeg2") {
     1166                        var frame = options["frame"] || 0;
     1167                        console.log(coding, "frame", frame);
     1168                        if (frame==0) {
     1169                                this.jsmpeg_decoder = jsmpeg();
     1170                        }
     1171                        var v = this.jsmpeg_decoder.decode(img_data);
     1172                        console.log("decoded:", v);
     1173                        painted();
     1174                }
    11631175                else if (coding=="h264") {
    11641176                        var frame = options["frame"] || 0;
    11651177                        if(frame==0) {
  • xpra/codecs/enc_ffmpeg/encoder.pyx

     
    282282    AVCodecID AV_CODEC_ID_VP8
    283283    AVCodecID AV_CODEC_ID_VP9
    284284    AVCodecID AV_CODEC_ID_MPEG4
     285    AVCodecID AV_CODEC_ID_MPEG1VIDEO
     286    AVCodecID AV_CODEC_ID_MPEG2VIDEO
    285287
    286288    AVCodecID AV_CODEC_ID_AAC
    287289
     
    633635#    CODECS.append("h265")
    634636if avcodec_find_encoder(AV_CODEC_ID_MPEG4)!=NULL:
    635637    CODECS.append("mpeg4+mp4")
     638if avcodec_find_encoder(AV_CODEC_ID_MPEG1VIDEO)!=NULL:
     639    CODECS.append("mpeg1")
     640if avcodec_find_encoder(AV_CODEC_ID_MPEG2VIDEO)!=NULL:
     641    CODECS.append("mpeg2")
    636642log("enc_ffmpeg CODECS=%s", csv(CODECS))
    637643
    638644DEF DEFAULT_BUF_LEN = 64*1024
     
    754760        assert encoding in CODECS
    755761        assert src_format in get_input_colorspaces(encoding), "invalid colorspace: %s" % src_format
    756762        self.encoding = encoding
    757         self.muxer_format = encoding.split("+")[1]  #ie: "mp4"   #"mov", "f4v"
    758         assert self.muxer_format in ("mp4", "webm")
     763        self.muxer_format = None
     764        if encoding.find("+")>0:
     765            self.muxer_format = encoding.split("+")[1]  #ie: "mpeg4+mp4" -> "mp4"   #"mov", "f4v"
     766            assert self.muxer_format in ("mp4", "webm")
    759767        self.width = width
    760768        self.height = height
    761769        self.src_format = src_format
     
    765773        self.buffers = []
    766774
    767775        codec = self.encoding.split("+")[0]
     776        log("init_context codec(%s)=%s", encoding, codec)
    768777        cdef AVCodecID video_codec_id
    769778        if codec=="h264":
    770779            video_codec_id = AV_CODEC_ID_H264
     
    776785            video_codec_id = AV_CODEC_ID_VP9
    777786        elif codec=="mpeg4":
    778787            video_codec_id = AV_CODEC_ID_MPEG4
     788        elif codec=="mpeg1":
     789            video_codec_id = AV_CODEC_ID_MPEG1VIDEO
     790        elif codec=="mpeg2":
     791            video_codec_id = AV_CODEC_ID_MPEG2VIDEO
    779792        else:
    780793            raise Exception("invalid codec; %s" % self.encoding)
    781794        self.video_codec = avcodec_find_encoder(video_codec_id)
     
    785798
    786799        #ie: client side as: "encoding.h264+mpeg4.YUV420P.profile" : "main"
    787800        profile = options.get("%s.%s.profile" % (self.encoding, src_format), "main")
     801        cdef uintptr_t gen = 0
    788802        try:
     803            if self.muxer_format:
     804                self.init_muxer(gen)
    789805            self.init_encoder(profile)
     806            gen = generation.increase()
     807            GEN_TO_ENCODER[gen] = self
     808            if SAVE_TO_FILE is not None:
     809                if self.muxer_format:
     810                    filename = SAVE_TO_FILE+"-"+self.encoding+"-"+str(gen)+".%s" % self.muxer_format
     811                else:
     812                    filename = SAVE_TO_FILE+"-"+str(gen)+"."+self.encoding
     813                self.file = open(filename, 'wb')
     814                log.info("saving %s stream to %s", self.encoding, filename)
    790815        except Exception as e:
    791816            log("init_encoder(%s) failed", profile, exc_info=True)
    792817            self.clean()
     
    794819        else:
    795820            log("enc_ffmpeg.Encoder.init_context(%s, %s, %s) self=%s", self.width, self.height, self.src_format, self.get_info())
    796821
    797     def init_encoder(self, profile):
    798         cdef AVDictionary *opts = NULL
     822
     823    def init_muxer(self, uintptr_t gen):
    799824        cdef AVDictionary *muxer_opts = NULL
    800825        global GEN_TO_ENCODER
    801         cdef AVOutputFormat *oformat = get_av_output_format(strtobytes(self.muxer_format))
     826        cdef AVOutputFormat *oformat = NULL
     827        oformat = get_av_output_format(strtobytes(self.muxer_format))
    802828        if oformat==NULL:
    803829            raise Exception("libavformat does not support %s" % self.muxer_format)
    804830        log("init_encoder() AVOutputFormat(%s)=%#x, flags=%s", self.muxer_format, <uintptr_t> oformat, flagscsv(AVFMT, oformat.flags))
     
    825851                msg = av_error_str(r)
    826852                raise Exception("failed to set %s muxer 'movflags' options '%s': %s" % (self.muxer_format, movflags, msg))
    827853
    828         cdef uintptr_t gen = generation.increase()
    829         GEN_TO_ENCODER[gen] = self
    830854        self.buffer = <unsigned char*> av_malloc(DEFAULT_BUF_LEN)
    831855        if self.buffer==NULL:
    832856            raise Exception("failed to allocate %iKB of memory" % (DEFAULT_BUF_LEN//1024))
     
    845869        self.video_stream.id = 0
    846870        log("init_encoder() video: avformat_new_stream=%#x, nb streams=%i", <uintptr_t> self.video_stream, self.muxer_ctx.nb_streams)
    847871
     872        log("init_encoder() writing %s header", self.muxer_format)
     873        r = avformat_write_header(self.muxer_ctx, &muxer_opts)
     874        av_dict_free(&muxer_opts)
     875        if r!=0:
     876            msg = av_error_str(r)
     877            raise Exception("libavformat failed to write header: %s" % msg)
     878
     879    def init_encoder(self, profile):
    848880        self.video_ctx = avcodec_alloc_context3(self.video_codec)
    849881        if self.video_ctx==NULL:
    850882            raise Exception("failed to allocate video codec context!")
     
    871903        #if oformat.flags & AVFMT_GLOBALHEADER:
    872904        self.video_ctx.flags |= AV_CODEC_FLAG_GLOBAL_HEADER
    873905        self.video_ctx.flags2 |= AV_CODEC_FLAG2_FAST   #may cause "no deblock across slices" - which should be fine
     906        cdef AVDictionary *opts = NULL
    874907        if self.encoding.startswith("h264") and profile:
    875908            r = av_dict_set(&opts, b"vprofile", strtobytes(profile), 0)
    876909            log("av_dict_set vprofile=%s returned %i", profile, r)
     
    899932        av_dict_free(&opts)
    900933        if r!=0:
    901934            raise Exception("could not open %s encoder context: %s" % (self.encoding, av_error_str(r)))
     935        log("avcodec_open2 success")
    902936
    903         r = avcodec_parameters_from_context(self.video_stream.codecpar, self.video_ctx)
    904         if r<0:
    905             raise Exception("could not copy video context parameters %#x: %s" % (<uintptr_t> self.video_stream.codecpar, av_error_str(r)))
     937        if self.video_stream:
     938            r = avcodec_parameters_from_context(self.video_stream.codecpar, self.video_ctx)
     939            if r<0:
     940                raise Exception("could not copy video context parameters %#x: %s" % (<uintptr_t> self.video_stream.codecpar, av_error_str(r)))
    906941
    907942        if AUDIO:
    908943            self.audio_codec = avcodec_find_encoder(AV_CODEC_ID_AAC)
     
    935970            if r<0:
    936971                raise Exception("could not copy audio context parameters %#x: %s" % (<uintptr_t> self.audio_stream.codecpar, av_error_str(r)))
    937972
    938         log("init_encoder() writing %s header", self.muxer_format)
    939         r = avformat_write_header(self.muxer_ctx, &muxer_opts)
    940         av_dict_free(&muxer_opts)
    941         if r!=0:
    942             msg = av_error_str(r)
    943             raise Exception("libavformat failed to write header: %s" % msg)
    944 
    945973        self.av_frame = av_frame_alloc()
    946974        if self.av_frame==NULL:
    947975            raise Exception("could not allocate an AVFrame for encoding")
    948976        self.frames = 0
    949977
    950         if SAVE_TO_FILE is not None:
    951             filename = SAVE_TO_FILE+"-"+self.encoding+"-"+str(gen)+".%s" % self.muxer_format
    952             self.file = open(filename, 'wb')
    953             log.info("saving %s stream to %s", self.encoding, filename)
    954978
    955 
    956979    def clean(self):
    957980        try:
    958981            self.clean_encoder()
     
    11291152            ret = avcodec_send_frame(self.video_ctx, frame)
    11301153        if ret!=0:
    11311154            self.log_av_error(image, ret, options)
    1132             raise Exception(av_error_str(ret))
     1155            raise Exception("%i: %s" % (ret, av_error_str(ret)))
    11331156
    11341157        buf_len = 1024+self.width*self.height
    11351158        av_init_packet(&avpkt)
     
    11401163        while ret==0:
    11411164            with nogil:
    11421165                ret = avcodec_receive_packet(self.video_ctx, &avpkt)
     1166            log("avcodec_receive_packet(..)=%i", ret)
    11431167            if ret==-errno.EAGAIN:
    11441168                log("ffmpeg avcodec_receive_packet EAGAIN")
    11451169                break
     
    11631187                self.log_error(image, "packet", options, "av packet is corrupt")
    11641188                raise Exception("av packet is corrupt")
    11651189
    1166             avpkt.stream_index = self.video_stream.index
    1167             r = av_write_frame(self.muxer_ctx, &avpkt)
    1168             log("av_write_frame packet returned %i", r)
    1169             if ret<0:
    1170                 free(avpkt.data)
    1171                 self.log_av_error(image, ret, options)
    1172                 raise Exception(av_error_str(ret))
    1173             while True:
    1174                 r = av_write_frame(self.muxer_ctx, NULL)
    1175                 log("av_write_frame flush returned %i", r)
    1176                 if r==1:
    1177                     break
     1190            if self.muxer_format:
     1191                avpkt.stream_index = self.video_stream.index
     1192                r = av_write_frame(self.muxer_ctx, &avpkt)
     1193                log("av_write_frame packet returned %i", r)
    11781194                if ret<0:
    11791195                    free(avpkt.data)
    11801196                    self.log_av_error(image, ret, options)
    11811197                    raise Exception(av_error_str(ret))
     1198                while True:
     1199                    r = av_write_frame(self.muxer_ctx, NULL)
     1200                    log("av_write_frame flush returned %i", r)
     1201                    if r==1:
     1202                        break
     1203                    if ret<0:
     1204                        free(avpkt.data)
     1205                        self.log_av_error(image, ret, options)
     1206                        raise Exception(av_error_str(ret))
     1207            else:
     1208                self.buffers.append(avpkt.data[:avpkt.size])
    11821209        av_packet_unref(&avpkt)
    11831210        free(avpkt.data)
    11841211        if self.frames==0 and self.profile:
     
    11871214        client_options["frame"] = int(self.frames)
    11881215        if self.frames==0:
    11891216            log("%s client options for first frame: %s", self.encoding, client_options)
    1190         self.frames += 1
    11911217        data = b"".join(self.buffers)
    1192         log("compress_image(%s) %5i bytes (%i buffers) for %4s frame %-3i, client options: %s", image, len(data), len(self.buffers), self.encoding, self.frames, client_options)
    11931218        if self.buffers and self.file:
    11941219            for x in self.buffers:
    11951220                self.file.write(x)
    11961221            self.file.flush()
    11971222        self.buffers = []
     1223        if self.encoding in ("mpeg1", "mpeg2"):
     1224            client_options["delayed"] = 1
     1225        self.frames += 1
     1226        log.info("compress_image(%s) %5i bytes (%i buffers) for %4s frame %-3i, client options: %s", image, len(data), len(self.buffers), self.encoding, self.frames, client_options)
    11981227        return data, client_options
    11991228
    12001229    def flush(self, delayed):
  • xpra/codecs/loader.py

     
    241241
    242242#note: this is just for defining the order of encodings,
    243243#so we have both core encodings (rgb24/rgb32) and regular encodings (rgb) in here:
    244 PREFERED_ENCODING_ORDER = ["h264", "vp9", "vp8", "mpeg4", "mpeg4+mp4", "h264+mp4", "vp8+webm", "vp9+webm", "png", "png/P", "png/L", "webp", "rgb", "rgb24", "rgb32", "jpeg", "h265", "jpeg2000"]
     244PREFERED_ENCODING_ORDER = ["h264", "vp9", "vp8", "mpeg4", "mpeg4+mp4", "h264+mp4", "vp8+webm", "vp9+webm", "png", "png/P", "png/L", "webp", "rgb", "rgb24", "rgb32", "jpeg", "h265", "jpeg2000", "mpeg1", "mpeg2"]
    245245#encoding order for edges (usually one pixel high or wide):
    246246EDGE_ENCODING_ORDER = ["rgb24", "rgb32", "jpeg", "png", "webp", "png/P", "png/L", "rgb"]
    247247