Re: [PATCH v6 08/26] server: Add VP8 support to the GStreamer encoder

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Thu, 22 Oct 2015, Christophe Fergeau wrote:

> On Wed, Oct 14, 2015 at 05:32:03PM +0200, Francois Gouget wrote:
> > The Spice server administrator can specify the preferred encoder and
> > codec preferences to optimize for CPU or bandwidth usage. Preferences
> > are described in a semi-colon separated list of encoder:codec pairs.
> > For instance 'gstreamer:vp8;spice:mjpeg' to pick first the GStreamer
> > VP8 video encoder and the original MJPEG video encoder as a fallback.
> > The server has a default preference list which can also be selected by
> > specifying 'auto' as the preferences list.
> 
> Note: All this paragraph describes a very different thing than what the
> shortlog says "server: Add VP8 support to the GStreamer encoder". Imo
> they are 2 distinct things, the addition of
> spice_server_set_video_codecs() and the addition of vp8 support to the
> gstreamer encoder, ie they should be (at least) 2 different commits. It
> might even make sense to move the client capability checks to a 3rd
> commit.

These are technically independent but conceptually they all depend on 
each other:
 * Adding VP8 support without a way to request using VP8 instead of 
   MJPEG would be equivalent to adding dead code. Furthermore if 
   compiling in GStreamer support forced use of VP8 then that server 
   would be incompatible with most clients so checking the client caps 
   is really necessary.

 * Committing a way to pick the encoder and codec when the only 
   codec is MJPEG does not make sense either. This could degenerate to 
   code that only lets the administrator pick the encoder (i.e. builting 
   or gstreamer), but the next patch would have to add support for the 
   codec and would essentially be just as big.

 * Committing the CAPS checking code first could work, though it would 
   be somewhat pointless and would not even shave a couple of lines off 
   this one.


> When adding use of SPICE_DISPLAY_CAP_MULTI_CODEC , I would raise the
> spice-protocol requirement in configure.ac to 0.12.11 (and do a
> post-release bump in spice-protocol git).

I have bumped the requirement to 0.12.11 in configure.ac but I believe 
the post-release bump in spice-protocol git has to be left to you.


> >      /* Start playing */
> >      spice_debug("setting state to PLAYING");
> > @@ -225,6 +274,12 @@ static gboolean construct_pipeline(SpiceGstEncoder *encoder,
> >  /* A helper for gst_encoder_encode_frame(). */
> >  static void reconfigure_pipeline(SpiceGstEncoder *encoder)
> >  {
> > +    if (encoder->base.codec_type == SPICE_VIDEO_CODEC_TYPE_VP8) {
> > +        /* vp8enc gets confused if we try to reconfigure the pipeline */
> > +        reset_pipeline(encoder);
> > +        return;
> > +    }
> 
> Any bug reference for this one? Just add it to the comment if there is
> such a bug, if not, that's fine.

vp8enc ignores our attempt to change the appsrc caps so that when it 
gets a buffer of the wrong size we get stuck. Given that VP8 performs 
inter-frame compression I cannot totally blame it for not liking the 
video format to change mid-stream. So while I'd prefer it if it could 
deal with this case, I'm not sure this warrants a vp8enc bug report. In 
any case this requires a workaround for now. I tried to make the comment 
more explicit.

Here are the corresponding log traces:

(/usr/bin/Xorg:26752): Spice-Debug **: gstreamer_encoder.c:415:gst_encoder_encode_frame: video format change: width 0 -> 640, height 0 -> 360, format 0 -> 9
[...]
(/usr/bin/Xorg:26752): Spice-Debug **: gstreamer_encoder.c:415:gst_encoder_encode_frame: video format change: width 640 -> 764, height 360 -> 448, format 9 -> 9
[...]
0:00:00.343781738 26752 0x7f9768544050 DEBUG          basetransform gstbasetransform.c:624:gst_base_transform_transform_size:<ffmpegcsp0> asked to transform size 1369088 for caps video/x-raw-rgb, bpp=(int)32, depth=(int)24, width=(int)640, height=(int)360, endianness=(int)4321, red_mask=(int)65280, green_mask=(int)16711680, blue_mask=(int)-16777216, framerate=(fraction)30/1 to size for caps video/x-raw-yuv, format=(fourcc)I420, width=(int)640, height=(int)360, framerate=(fraction)30/1 in direction SINK
** (Xorg:26752): WARNING **: ffmpegcsp0: size 1369088 is not a multiple of unit size 921600

See also:
http://lists.freedesktop.org/archives/spice-devel/2015-August/021274.html



> > @@ -1349,10 +1349,12 @@ static void mjpeg_encoder_get_stats(VideoEncoder *video_encoder,
> >      stats->avg_quality = (double)encoder->avg_quality / encoder->num_frames;
> >  }
> >  
> > -VideoEncoder *mjpeg_encoder_new(uint64_t starting_bit_rate,
> > +VideoEncoder *mjpeg_encoder_new(SpiceVideoCodecType codec_type,
> > +                                uint64_t starting_bit_rate,
> >                                  VideoEncoderRateControlCbs *cbs,
> >                                  void *cbs_opaque)
> >  {
> > +    spice_assert(codec_type == SPICE_VIDEO_CODEC_TYPE_MJPEG);
> 
> I'd make that g_return_val_if_fail(codec_type ==
> SPICE_VIDEO_CODEC_TYPE_MJPEG);

mjpeg_encoder.c does not depend on glib.h currently. The g_return_xxx() 
functions are also very rarely used in the Spice server: only twice in 
reds_stream.c. Furthermore calling mjpeg_encoder_new() for anything but 
the MJPEG codec can only result from a coding error. So I think 
spice_assert() is appropriate here.

See also:
http://lists.freedesktop.org/archives/spice-devel/2015-July/021161.html


> > +int red_dispatcher_set_video_codecs(const char *codecs)
> > +{
> > +    uint32_t encoder;
> > +    SpiceVideoCodecType type;
> > +    uint32_t cap;
> > +    char *encoder_name, *codec_name;
> > +    static RedVideoCodec new_codecs[RED_MAX_VIDEO_CODECS];
> > +    int count;
> > +    const char* c;
> > +
> > +    if (strcmp(codecs, "auto") == 0) {
> > +        codecs = VIDEO_ENCODER_DEFAULT_PREFERENCE;
> > +    }
> > +
> > +    c = codecs;
> > +    count = 0;
> > +    while ( (c = parse_video_codecs(c, &encoder_name, &codec_name)) ) {
> 
> Might be simpler to parse with g_strsplit() and strstr or such, but your
> way is ok (though took me a while to find what sscanf(%m) is doing!)

I was initially using a more manual way of parsing the string but Victor 
Toso recommended using sscanf which did lead to shorter code:
http://lists.freedesktop.org/archives/spice-devel/2015-July/021161.html


> > @@ -3108,10 +3135,15 @@ static void red_display_create_stream(DisplayChannelClient *dcc, Stream *stream)
> >          video_cbs.update_client_playback_delay = red_stream_update_client_playback_latency;
> >  
> >          initial_bit_rate = red_stream_get_initial_bit_rate(dcc, stream);
> > -        agent->video_encoder = red_display_create_video_encoder(initial_bit_rate, &video_cbs, agent);
> > +        agent->video_encoder = red_display_create_video_encoder(dcc, initial_bit_rate, &video_cbs, agent);
> >      } else {
> > -        agent->video_encoder = red_display_create_video_encoder(0, NULL, NULL);
> > +        agent->video_encoder = red_display_create_video_encoder(dcc, 0, NULL, NULL);
> >      }
> > +    if (agent->video_encoder == NULL) {
> > +        stream->refs--;
> > +        return FALSE;
> > +    }
> > +
> 
> Have you tested this error path? What happens when we destroy the stream
> this way? bad rendering, or just fall back to no streaming?

If I remember correctly (I tested this months ago), it goes back to no 
streaming. I don't remember if I got it to stop trying to initiate the 
stream over and over again though.


-- 
Francois Gouget <fgouget@xxxxxxxxxxxxxxx>
_______________________________________________
Spice-devel mailing list
Spice-devel@xxxxxxxxxxxxxxxxxxxxx
http://lists.freedesktop.org/mailman/listinfo/spice-devel




[Index of Archives]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [IETF Annouce]     [Security]     [Bugtraq]     [Linux]     [Linux OMAP]     [Linux MIPS]     [ECOS]     [Asterisk Internet PBX]     [Linux API]     [Monitors]