20#include <freerdp/config.h> 
   27#include <winpr/assert.h> 
   28#include <winpr/cast.h> 
   29#include <winpr/synch.h> 
   30#include <winpr/print.h> 
   31#include <winpr/stream.h> 
   32#include <winpr/cmdline.h> 
   33#include <winpr/collections.h> 
   34#include <winpr/interlocked.h> 
   35#include <winpr/sysinfo.h> 
   37#include <freerdp/addin.h> 
   38#include <freerdp/primitives.h> 
   39#include <freerdp/client/channels.h> 
   40#include <freerdp/client/geometry.h> 
   41#include <freerdp/client/video.h> 
   42#include <freerdp/channels/log.h> 
   43#include <freerdp/codec/h264.h> 
   44#include <freerdp/codec/yuv.h> 
   45#include <freerdp/timer.h> 
   47#define TAG CHANNELS_TAG("video") 
   49#include "video_main.h" 
   55  IWTSListener* controlListener;
 
   56  IWTSListener* dataListener;
 
   60  VideoClientContext* context;
 
   62  rdpContext* rdpcontext;
 
   65#define XF_VIDEO_UNLIMITED_RATE 31 
   67static const BYTE MFVideoFormat_H264[] = { 
'H',  
'2',  
'6',  
'4',  0x00, 0x00, 0x10, 0x00,
 
   68                                         0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71 };
 
   72  VideoClientContext* video;
 
   74  UINT32 ScaledWidth, ScaledHeight;
 
   75  MAPPED_GEOMETRY* geometry;
 
   77  UINT64 startTimeStamp;
 
   81  UINT64 lastPublishTime, nextPublishTime;
 
   82  volatile LONG refCounter;
 
   90  MAPPED_GEOMETRY* geometry;
 
   94  PresentationContext* presentation;
 
   98struct s_VideoClientContextPriv
 
  100  VideoClientContext* video;
 
  101  GeometryClientContext* geometry;
 
  104  wBufferPool* surfacePool;
 
  105  UINT32 publishedFrames;
 
  106  UINT32 droppedFrames;
 
  108  UINT64 nextFeedbackTime;
 
  109  PresentationContext* currentPresentation;
 
  110  FreeRDP_TimerID timerID;
 
  113static void PresentationContext_unref(PresentationContext** presentation);
 
  114static void VideoClientContextPriv_free(VideoClientContextPriv* priv);
 
  116static const char* video_command_name(BYTE cmd)
 
  120    case TSMM_START_PRESENTATION:
 
  122    case TSMM_STOP_PRESENTATION:
 
  129static void video_client_context_set_geometry(VideoClientContext* video,
 
  130                                              GeometryClientContext* geometry)
 
  133  WINPR_ASSERT(video->priv);
 
  134  video->priv->geometry = geometry;
 
  137static VideoClientContextPriv* VideoClientContextPriv_new(VideoClientContext* video)
 
  139  VideoClientContextPriv* ret = NULL;
 
  142  ret = calloc(1, 
sizeof(*ret));
 
  146  ret->frames = Queue_New(TRUE, 10, 2);
 
  149    WLog_ERR(TAG, 
"unable to allocate frames queue");
 
  153  ret->surfacePool = BufferPool_New(FALSE, 0, 16);
 
  154  if (!ret->surfacePool)
 
  156    WLog_ERR(TAG, 
"unable to create surface pool");
 
  160  if (!InitializeCriticalSectionAndSpinCount(&ret->framesLock, 4 * 1000))
 
  162    WLog_ERR(TAG, 
"unable to initialize frames lock");
 
  171  ret->lastSentRate = 30;
 
  175  VideoClientContextPriv_free(ret);
 
  179static BOOL PresentationContext_ref(PresentationContext* presentation)
 
  181  WINPR_ASSERT(presentation);
 
  183  InterlockedIncrement(&presentation->refCounter);
 
  187static PresentationContext* PresentationContext_new(VideoClientContext* video, BYTE PresentationId,
 
  188                                                    UINT32 x, UINT32 y, UINT32 width, UINT32 height)
 
  190  size_t s = 4ULL * width * height;
 
  191  PresentationContext* ret = NULL;
 
  198  ret = calloc(1, 
sizeof(*ret));
 
  203  ret->PresentationId = PresentationId;
 
  205  ret->h264 = h264_context_new(FALSE);
 
  208    WLog_ERR(TAG, 
"unable to create a h264 context");
 
  211  if (!h264_context_reset(ret->h264, width, height))
 
  214  ret->currentSample = Stream_New(NULL, 4096);
 
  215  if (!ret->currentSample)
 
  217    WLog_ERR(TAG, 
"unable to create current packet stream");
 
  221  ret->surface = video->createSurface(video, x, y, width, height);
 
  224    WLog_ERR(TAG, 
"unable to create surface");
 
  228  if (!PresentationContext_ref(ret))
 
  234  PresentationContext_unref(&ret);
 
  238static void PresentationContext_unref(PresentationContext** ppresentation)
 
  240  PresentationContext* presentation = NULL;
 
  241  MAPPED_GEOMETRY* geometry = NULL;
 
  243  WINPR_ASSERT(ppresentation);
 
  245  presentation = *ppresentation;
 
  249  if (InterlockedDecrement(&presentation->refCounter) > 0)
 
  252  geometry = presentation->geometry;
 
  255    geometry->MappedGeometryUpdate = NULL;
 
  256    geometry->MappedGeometryClear = NULL;
 
  257    geometry->custom = NULL;
 
  258    mappedGeometryUnref(geometry);
 
  261  h264_context_free(presentation->h264);
 
  262  Stream_Free(presentation->currentSample, TRUE);
 
  263  presentation->video->deleteSurface(presentation->video, presentation->surface);
 
  265  *ppresentation = NULL;
 
  268static void VideoFrame_free(VideoFrame** pframe)
 
  270  VideoFrame* frame = NULL;
 
  272  WINPR_ASSERT(pframe);
 
  277  mappedGeometryUnref(frame->geometry);
 
  279  WINPR_ASSERT(frame->presentation);
 
  280  WINPR_ASSERT(frame->presentation->video);
 
  281  WINPR_ASSERT(frame->presentation->video->priv);
 
  282  BufferPool_Return(frame->presentation->video->priv->surfacePool, frame->surfaceData);
 
  283  PresentationContext_unref(&frame->presentation);
 
  288static VideoFrame* VideoFrame_new(VideoClientContextPriv* priv, PresentationContext* presentation,
 
  289                                  MAPPED_GEOMETRY* geom)
 
  291  VideoFrame* frame = NULL;
 
  295  WINPR_ASSERT(presentation);
 
  298  surface = presentation->surface;
 
  299  WINPR_ASSERT(surface);
 
  301  frame = calloc(1, 
sizeof(VideoFrame));
 
  305  mappedGeometryRef(geom);
 
  307  frame->publishTime = presentation->lastPublishTime;
 
  308  frame->geometry = geom;
 
  309  frame->w = surface->alignedWidth;
 
  310  frame->h = surface->alignedHeight;
 
  311  frame->scanline = surface->scanline;
 
  313  frame->surfaceData = BufferPool_Take(priv->surfacePool, 1ll * frame->scanline * frame->h);
 
  314  if (!frame->surfaceData)
 
  317  frame->presentation = presentation;
 
  318  if (!PresentationContext_ref(frame->presentation))
 
  324  VideoFrame_free(&frame);
 
  328void VideoClientContextPriv_free(VideoClientContextPriv* priv)
 
  333  EnterCriticalSection(&priv->framesLock);
 
  337    while (Queue_Count(priv->frames))
 
  339      VideoFrame* frame = Queue_Dequeue(priv->frames);
 
  341        VideoFrame_free(&frame);
 
  345  Queue_Free(priv->frames);
 
  346  LeaveCriticalSection(&priv->framesLock);
 
  348  DeleteCriticalSection(&priv->framesLock);
 
  350  if (priv->currentPresentation)
 
  351    PresentationContext_unref(&priv->currentPresentation);
 
  353  BufferPool_Free(priv->surfacePool);
 
  357static UINT video_control_send_presentation_response(VideoClientContext* context,
 
  360  BYTE buf[12] = { 0 };
 
  362  VIDEO_PLUGIN* video = NULL;
 
  363  IWTSVirtualChannel* channel = NULL;
 
  366  WINPR_ASSERT(context);
 
  369  video = (VIDEO_PLUGIN*)context->handle;
 
  372  s = Stream_New(buf, 12);
 
  374    return CHANNEL_RC_NO_MEMORY;
 
  376  Stream_Write_UINT32(s, 12);                                     
 
  377  Stream_Write_UINT32(s, TSMM_PACKET_TYPE_PRESENTATION_RESPONSE); 
 
  378  Stream_Write_UINT8(s, resp->PresentationId);
 
  380  Stream_SealLength(s);
 
  382  channel = video->control_callback->channel_callback->channel;
 
  383  ret = channel->Write(channel, 12, buf, NULL);
 
  384  Stream_Free(s, FALSE);
 
  389static BOOL video_onMappedGeometryUpdate(MAPPED_GEOMETRY* geometry)
 
  391  PresentationContext* presentation = NULL;
 
  394  WINPR_ASSERT(geometry);
 
  396  presentation = (PresentationContext*)geometry->custom;
 
  397  WINPR_ASSERT(presentation);
 
  399  r = &geometry->geometry.boundingRect;
 
  401           "geometry updated topGeom=(%" PRId32 
",%" PRId32 
"-%" PRId32 
"x%" PRId32
 
  402           ") geom=(%" PRId32 
",%" PRId32 
"-%" PRId32 
"x%" PRId32 
") rects=(%" PRId16 
",%" PRId16
 
  403           "-%" PRId16 
"x%" PRId16 
")",
 
  404           geometry->topLevelLeft, geometry->topLevelTop,
 
  405           geometry->topLevelRight - geometry->topLevelLeft,
 
  406           geometry->topLevelBottom - geometry->topLevelTop,
 
  408           geometry->left, geometry->top, geometry->right - geometry->left,
 
  409           geometry->bottom - geometry->top,
 
  411           r->x, r->y, r->width, r->height);
 
  413  presentation->surface->x =
 
  414      WINPR_ASSERTING_INT_CAST(uint32_t, geometry->topLevelLeft + geometry->left);
 
  415  presentation->surface->y =
 
  416      WINPR_ASSERTING_INT_CAST(uint32_t, geometry->topLevelTop + geometry->top);
 
  421static BOOL video_onMappedGeometryClear(MAPPED_GEOMETRY* geometry)
 
  423  PresentationContext* presentation = NULL;
 
  425  WINPR_ASSERT(geometry);
 
  427  presentation = (PresentationContext*)geometry->custom;
 
  428  WINPR_ASSERT(presentation);
 
  430  mappedGeometryUnref(presentation->geometry);
 
  431  presentation->geometry = NULL;
 
  435static UINT video_PresentationRequest(VideoClientContext* video,
 
  438  UINT ret = CHANNEL_RC_OK;
 
  443  VideoClientContextPriv* priv = video->priv;
 
  446  if (req->Command == TSMM_START_PRESENTATION)
 
  448    MAPPED_GEOMETRY* geom = NULL;
 
  451    if (memcmp(req->VideoSubtypeId, MFVideoFormat_H264, 16) != 0)
 
  453      WLog_ERR(TAG, 
"not a H264 video, ignoring request");
 
  454      return CHANNEL_RC_OK;
 
  457    if (priv->currentPresentation)
 
  459      if (priv->currentPresentation->PresentationId == req->PresentationId)
 
  461        WLog_ERR(TAG, 
"ignoring start request for existing presentation %" PRIu8,
 
  462                 req->PresentationId);
 
  463        return CHANNEL_RC_OK;
 
  466      WLog_ERR(TAG, 
"releasing current presentation %" PRIu8, req->PresentationId);
 
  467      PresentationContext_unref(&priv->currentPresentation);
 
  472      WLog_ERR(TAG, 
"geometry channel not ready, ignoring request");
 
  473      return CHANNEL_RC_OK;
 
  476    geom = HashTable_GetItemValue(priv->geometry->geometries, &(req->GeometryMappingId));
 
  479      WLog_ERR(TAG, 
"geometry mapping 0x%" PRIx64 
" not registered", req->GeometryMappingId);
 
  480      return CHANNEL_RC_OK;
 
  483    WLog_DBG(TAG, 
"creating presentation 0x%x", req->PresentationId);
 
  484    priv->currentPresentation = PresentationContext_new(
 
  485        video, req->PresentationId,
 
  486        WINPR_ASSERTING_INT_CAST(uint32_t, geom->topLevelLeft + geom->left),
 
  487        WINPR_ASSERTING_INT_CAST(uint32_t, geom->topLevelTop + geom->top), req->SourceWidth,
 
  489    if (!priv->currentPresentation)
 
  491      WLog_ERR(TAG, 
"unable to create presentation video");
 
  492      return CHANNEL_RC_NO_MEMORY;
 
  495    mappedGeometryRef(geom);
 
  496    priv->currentPresentation->geometry = geom;
 
  498    priv->currentPresentation->video = video;
 
  499    priv->currentPresentation->ScaledWidth = req->ScaledWidth;
 
  500    priv->currentPresentation->ScaledHeight = req->ScaledHeight;
 
  502    geom->custom = priv->currentPresentation;
 
  503    geom->MappedGeometryUpdate = video_onMappedGeometryUpdate;
 
  504    geom->MappedGeometryClear = video_onMappedGeometryClear;
 
  507    resp.PresentationId = req->PresentationId;
 
  508    ret = video_control_send_presentation_response(video, &resp);
 
  510  else if (req->Command == TSMM_STOP_PRESENTATION)
 
  512    WLog_DBG(TAG, 
"stopping presentation 0x%x", req->PresentationId);
 
  513    if (!priv->currentPresentation)
 
  515      WLog_ERR(TAG, 
"unknown presentation to stop %" PRIu8, req->PresentationId);
 
  516      return CHANNEL_RC_OK;
 
  519    priv->droppedFrames = 0;
 
  520    priv->publishedFrames = 0;
 
  521    PresentationContext_unref(&priv->currentPresentation);
 
  527static UINT video_read_tsmm_presentation_req(VideoClientContext* context, 
wStream* s)
 
  531  WINPR_ASSERT(context);
 
  534  if (!Stream_CheckAndLogRequiredLength(TAG, s, 60))
 
  535    return ERROR_INVALID_DATA;
 
  537  Stream_Read_UINT8(s, req.PresentationId);
 
  538  Stream_Read_UINT8(s, req.Version);
 
  539  Stream_Read_UINT8(s, req.Command);
 
  540  Stream_Read_UINT8(s, req.FrameRate); 
 
  542  Stream_Seek_UINT16(s); 
 
  543  Stream_Seek_UINT16(s); 
 
  545  Stream_Read_UINT32(s, req.SourceWidth);
 
  546  Stream_Read_UINT32(s, req.SourceHeight);
 
  547  Stream_Read_UINT32(s, req.ScaledWidth);
 
  548  Stream_Read_UINT32(s, req.ScaledHeight);
 
  549  Stream_Read_UINT64(s, req.hnsTimestampOffset);
 
  550  Stream_Read_UINT64(s, req.GeometryMappingId);
 
  551  Stream_Read(s, req.VideoSubtypeId, 16);
 
  553  Stream_Read_UINT32(s, req.cbExtra);
 
  555  if (!Stream_CheckAndLogRequiredLength(TAG, s, req.cbExtra))
 
  556    return ERROR_INVALID_DATA;
 
  558  req.pExtraData = Stream_Pointer(s);
 
  561           "presentationReq: id:%" PRIu8 
" version:%" PRIu8
 
  562           " command:%s srcWidth/srcHeight=%" PRIu32 
"x%" PRIu32 
" scaled Width/Height=%" PRIu32
 
  563           "x%" PRIu32 
" timestamp=%" PRIu64 
" mappingId=%" PRIx64 
"",
 
  564           req.PresentationId, req.Version, video_command_name(req.Command), req.SourceWidth,
 
  565           req.SourceHeight, req.ScaledWidth, req.ScaledHeight, req.hnsTimestampOffset,
 
  566           req.GeometryMappingId);
 
  568  return video_PresentationRequest(context, &req);
 
  576static UINT video_control_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, 
wStream* s)
 
  579  VIDEO_PLUGIN* video = NULL;
 
  580  VideoClientContext* context = NULL;
 
  581  UINT ret = CHANNEL_RC_OK;
 
  583  UINT32 packetType = 0;
 
  585  WINPR_ASSERT(callback);
 
  588  video = (VIDEO_PLUGIN*)callback->plugin;
 
  591  context = (VideoClientContext*)video->wtsPlugin.pInterface;
 
  592  WINPR_ASSERT(context);
 
  594  if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
 
  595    return ERROR_INVALID_DATA;
 
  597  Stream_Read_UINT32(s, cbSize);
 
  600    WLog_ERR(TAG, 
"invalid cbSize %" PRIu32 
", expected 8", cbSize);
 
  601    return ERROR_INVALID_DATA;
 
  603  if (!Stream_CheckAndLogRequiredLength(TAG, s, cbSize - 4))
 
  604    return ERROR_INVALID_DATA;
 
  606  Stream_Read_UINT32(s, packetType);
 
  609    case TSMM_PACKET_TYPE_PRESENTATION_REQUEST:
 
  610      ret = video_read_tsmm_presentation_req(context, s);
 
  613      WLog_ERR(TAG, 
"not expecting packet type %" PRIu32 
"", packetType);
 
  614      ret = ERROR_UNSUPPORTED_TYPE;
 
  621static UINT video_control_send_client_notification(VideoClientContext* context,
 
  626  VIDEO_PLUGIN* video = NULL;
 
  627  IWTSVirtualChannel* channel = NULL;
 
  631  WINPR_ASSERT(context);
 
  634  video = (VIDEO_PLUGIN*)context->handle;
 
  637  s = Stream_New(buf, 32);
 
  639    return CHANNEL_RC_NO_MEMORY;
 
  642  Stream_Seek_UINT32(s);                                        
 
  643  Stream_Write_UINT32(s, TSMM_PACKET_TYPE_CLIENT_NOTIFICATION); 
 
  644  Stream_Write_UINT8(s, notif->PresentationId);
 
  645  Stream_Write_UINT8(s, notif->NotificationType);
 
  647  if (notif->NotificationType == TSMM_CLIENT_NOTIFICATION_TYPE_FRAMERATE_OVERRIDE)
 
  649    Stream_Write_UINT32(s, 16); 
 
  652    Stream_Write_UINT32(s, notif->FramerateOverride.Flags);
 
  653    Stream_Write_UINT32(s, notif->FramerateOverride.DesiredFrameRate);
 
  654    Stream_Zero(s, 4ULL * 2ULL);
 
  660    Stream_Write_UINT32(s, 0); 
 
  663  Stream_SealLength(s);
 
  664  Stream_SetPosition(s, 0);
 
  665  Stream_Write_UINT32(s, cbSize);
 
  666  Stream_Free(s, FALSE);
 
  668  WINPR_ASSERT(video->control_callback);
 
  669  WINPR_ASSERT(video->control_callback->channel_callback);
 
  671  channel = video->control_callback->channel_callback->channel;
 
  672  WINPR_ASSERT(channel);
 
  673  WINPR_ASSERT(channel->Write);
 
  675  ret = channel->Write(channel, cbSize, buf, NULL);
 
  680static void video_timer(VideoClientContext* video, UINT64 now)
 
  682  PresentationContext* presentation = NULL;
 
  683  VideoClientContextPriv* priv = NULL;
 
  684  VideoFrame* peekFrame = NULL;
 
  685  VideoFrame* frame = NULL;
 
  692  EnterCriticalSection(&priv->framesLock);
 
  695    peekFrame = (VideoFrame*)Queue_Peek(priv->frames);
 
  699    if (peekFrame->publishTime > now)
 
  704      WLog_DBG(TAG, 
"dropping frame @%" PRIu64, frame->publishTime);
 
  705      priv->droppedFrames++;
 
  706      VideoFrame_free(&frame);
 
  709    Queue_Dequeue(priv->frames);
 
  711  LeaveCriticalSection(&priv->framesLock);
 
  716  presentation = frame->presentation;
 
  718  priv->publishedFrames++;
 
  719  memcpy(presentation->surface->data, frame->surfaceData, 1ull * frame->scanline * frame->h);
 
  721  WINPR_ASSERT(video->showSurface);
 
  722  video->showSurface(video, presentation->surface, presentation->ScaledWidth,
 
  723                     presentation->ScaledHeight);
 
  725  VideoFrame_free(&frame);
 
  728  if (priv->nextFeedbackTime < now)
 
  733    if (priv->publishedFrames && priv->currentPresentation)
 
  735      UINT32 computedRate = 0;
 
  737      PresentationContext_ref(priv->currentPresentation);
 
  739      if (priv->droppedFrames)
 
  746        if (priv->lastSentRate == XF_VIDEO_UNLIMITED_RATE)
 
  750          computedRate = priv->lastSentRate - 2;
 
  761        if (priv->lastSentRate == XF_VIDEO_UNLIMITED_RATE)
 
  762          computedRate = XF_VIDEO_UNLIMITED_RATE; 
 
  765          computedRate = priv->lastSentRate + 2;
 
  766          if (computedRate > XF_VIDEO_UNLIMITED_RATE)
 
  767            computedRate = XF_VIDEO_UNLIMITED_RATE;
 
  771      if (computedRate != priv->lastSentRate)
 
  775        WINPR_ASSERT(priv->currentPresentation);
 
  776        notif.PresentationId = priv->currentPresentation->PresentationId;
 
  777        notif.NotificationType = TSMM_CLIENT_NOTIFICATION_TYPE_FRAMERATE_OVERRIDE;
 
  778        if (computedRate == XF_VIDEO_UNLIMITED_RATE)
 
  780          notif.FramerateOverride.Flags = 0x01;
 
  781          notif.FramerateOverride.DesiredFrameRate = 0x00;
 
  785          notif.FramerateOverride.Flags = 0x02;
 
  786          notif.FramerateOverride.DesiredFrameRate = computedRate;
 
  789        video_control_send_client_notification(video, ¬if);
 
  790        priv->lastSentRate = computedRate;
 
  793                 "server notified with rate %" PRIu32 
" published=%" PRIu32
 
  795                 priv->lastSentRate, priv->publishedFrames, priv->droppedFrames);
 
  798      PresentationContext_unref(&priv->currentPresentation);
 
  801    WLog_DBG(TAG, 
"currentRate=%" PRIu32 
" published=%" PRIu32 
" dropped=%" PRIu32,
 
  802             priv->lastSentRate, priv->publishedFrames, priv->droppedFrames);
 
  804    priv->droppedFrames = 0;
 
  805    priv->publishedFrames = 0;
 
  806    priv->nextFeedbackTime = now + 1000;
 
  810static UINT video_VideoData(VideoClientContext* context, 
const TSMM_VIDEO_DATA* data)
 
  812  VideoClientContextPriv* priv = NULL;
 
  813  PresentationContext* presentation = NULL;
 
  816  WINPR_ASSERT(context);
 
  819  priv = context->priv;
 
  822  presentation = priv->currentPresentation;
 
  825    WLog_ERR(TAG, 
"no current presentation");
 
  826    return CHANNEL_RC_OK;
 
  829  if (presentation->PresentationId != data->PresentationId)
 
  831    WLog_ERR(TAG, 
"current presentation id=%" PRIu8 
" doesn't match data id=%" PRIu8,
 
  832             presentation->PresentationId, data->PresentationId);
 
  833    return CHANNEL_RC_OK;
 
  836  if (!Stream_EnsureRemainingCapacity(presentation->currentSample, data->cbSample))
 
  838    WLog_ERR(TAG, 
"unable to expand the current packet");
 
  839    return CHANNEL_RC_NO_MEMORY;
 
  842  Stream_Write(presentation->currentSample, data->pSample, data->cbSample);
 
  844  if (data->CurrentPacketIndex == data->PacketsInSample)
 
  847    H264_CONTEXT* h264 = presentation->h264;
 
  848    UINT64 startTime = GetTickCount64();
 
  849    UINT64 timeAfterH264 = 0;
 
  850    MAPPED_GEOMETRY* geom = presentation->geometry;
 
  852    const RECTANGLE_16 rect = { 0, 0, WINPR_ASSERTING_INT_CAST(UINT16, surface->alignedWidth),
 
  853                              WINPR_ASSERTING_INT_CAST(UINT16, surface->alignedHeight) };
 
  854    Stream_SealLength(presentation->currentSample);
 
  855    Stream_SetPosition(presentation->currentSample, 0);
 
  857    timeAfterH264 = GetTickCount64();
 
  858    if (data->SampleNumber == 1)
 
  860      presentation->lastPublishTime = startTime;
 
  863    presentation->lastPublishTime += (data->hnsDuration / 10000);
 
  864    if (presentation->lastPublishTime <= timeAfterH264 + 10)
 
  868      const size_t len = Stream_Length(presentation->currentSample);
 
  869      if (len > UINT32_MAX)
 
  870        return CHANNEL_RC_OK;
 
  874          avc420_decompress(h264, Stream_Pointer(presentation->currentSample), (UINT32)len,
 
  875                            surface->data, surface->format, surface->scanline,
 
  876                            surface->alignedWidth, surface->alignedHeight, &rect, 1);
 
  879        return CHANNEL_RC_OK;
 
  881      WINPR_ASSERT(context->showSurface);
 
  882      context->showSurface(context, presentation->surface, presentation->ScaledWidth,
 
  883                           presentation->ScaledHeight);
 
  885      priv->publishedFrames++;
 
  888      EnterCriticalSection(&priv->framesLock);
 
  889      while (Queue_Count(priv->frames) > 0)
 
  891        VideoFrame* frame = Queue_Dequeue(priv->frames);
 
  894          priv->droppedFrames++;
 
  895          VideoFrame_free(&frame);
 
  899      LeaveCriticalSection(&priv->framesLock);
 
  902        WLog_DBG(TAG, 
"showing frame (%d dropped)", dropped);
 
  906      const size_t len = Stream_Length(presentation->currentSample);
 
  907      if (len > UINT32_MAX)
 
  908        return CHANNEL_RC_OK;
 
  910      BOOL enqueueResult = 0;
 
  911      VideoFrame* frame = VideoFrame_new(priv, presentation, geom);
 
  914        WLog_ERR(TAG, 
"unable to create frame");
 
  915        return CHANNEL_RC_NO_MEMORY;
 
  919          avc420_decompress(h264, Stream_Pointer(presentation->currentSample), (UINT32)len,
 
  920                            frame->surfaceData, surface->format, surface->scanline,
 
  921                            surface->alignedWidth, surface->alignedHeight, &rect, 1);
 
  924        VideoFrame_free(&frame);
 
  925        return CHANNEL_RC_OK;
 
  928      EnterCriticalSection(&priv->framesLock);
 
  929      enqueueResult = Queue_Enqueue(priv->frames, frame);
 
  930      LeaveCriticalSection(&priv->framesLock);
 
  934        WLog_ERR(TAG, 
"unable to enqueue frame");
 
  935        VideoFrame_free(&frame);
 
  936        return CHANNEL_RC_NO_MEMORY;
 
  940      WLog_DBG(TAG, 
"scheduling frame in %" PRIu32 
" ms", (frame->publishTime - startTime));
 
  944  return CHANNEL_RC_OK;
 
  947static UINT video_data_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, 
wStream* s)
 
  950  VIDEO_PLUGIN* video = NULL;
 
  951  VideoClientContext* context = NULL;
 
  953  UINT32 packetType = 0;
 
  956  video = (VIDEO_PLUGIN*)callback->plugin;
 
  957  context = (VideoClientContext*)video->wtsPlugin.pInterface;
 
  959  if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
 
  960    return ERROR_INVALID_DATA;
 
  962  Stream_Read_UINT32(s, cbSize);
 
  965    WLog_ERR(TAG, 
"invalid cbSize %" PRIu32 
", expected >= 8", cbSize);
 
  966    return ERROR_INVALID_DATA;
 
  969  if (!Stream_CheckAndLogRequiredLength(TAG, s, cbSize - 4))
 
  970    return ERROR_INVALID_DATA;
 
  972  Stream_Read_UINT32(s, packetType);
 
  973  if (packetType != TSMM_PACKET_TYPE_VIDEO_DATA)
 
  975    WLog_ERR(TAG, 
"only expecting VIDEO_DATA on the data channel");
 
  976    return ERROR_INVALID_DATA;
 
  979  if (!Stream_CheckAndLogRequiredLength(TAG, s, 32))
 
  980    return ERROR_INVALID_DATA;
 
  982  Stream_Read_UINT8(s, data.PresentationId);
 
  983  Stream_Read_UINT8(s, data.Version);
 
  984  Stream_Read_UINT8(s, data.Flags);
 
  985  Stream_Seek_UINT8(s); 
 
  986  Stream_Read_UINT64(s, data.hnsTimestamp);
 
  987  Stream_Read_UINT64(s, data.hnsDuration);
 
  988  Stream_Read_UINT16(s, data.CurrentPacketIndex);
 
  989  Stream_Read_UINT16(s, data.PacketsInSample);
 
  990  Stream_Read_UINT32(s, data.SampleNumber);
 
  991  Stream_Read_UINT32(s, data.cbSample);
 
  992  if (!Stream_CheckAndLogRequiredLength(TAG, s, data.cbSample))
 
  993    return ERROR_INVALID_DATA;
 
  994  data.pSample = Stream_Pointer(s);
 
 1004  return video_VideoData(context, &data);
 
 1012static UINT video_control_on_close(IWTSVirtualChannelCallback* pChannelCallback)
 
 1014  free(pChannelCallback);
 
 1015  return CHANNEL_RC_OK;
 
 1018static UINT video_data_on_close(IWTSVirtualChannelCallback* pChannelCallback)
 
 1020  free(pChannelCallback);
 
 1021  return CHANNEL_RC_OK;
 
 1030static UINT video_control_on_new_channel_connection(IWTSListenerCallback* listenerCallback,
 
 1031                                                    IWTSVirtualChannel* channel, BYTE* Data,
 
 1033                                                    IWTSVirtualChannelCallback** ppCallback)
 
 1040  WINPR_UNUSED(pbAccept);
 
 1045    WLog_ERR(TAG, 
"calloc failed!");
 
 1046    return CHANNEL_RC_NO_MEMORY;
 
 1049  callback->iface.OnDataReceived = video_control_on_data_received;
 
 1050  callback->iface.OnClose = video_control_on_close;
 
 1051  callback->plugin = listener_callback->plugin;
 
 1052  callback->channel_mgr = listener_callback->channel_mgr;
 
 1053  callback->channel = channel;
 
 1054  listener_callback->channel_callback = callback;
 
 1056  *ppCallback = (IWTSVirtualChannelCallback*)callback;
 
 1058  return CHANNEL_RC_OK;
 
 1062static UINT video_data_on_new_channel_connection(IWTSListenerCallback* pListenerCallback,
 
 1063                                                 IWTSVirtualChannel* pChannel, BYTE* Data,
 
 1065                                                 IWTSVirtualChannelCallback** ppCallback)
 
 1072  WINPR_UNUSED(pbAccept);
 
 1077    WLog_ERR(TAG, 
"calloc failed!");
 
 1078    return CHANNEL_RC_NO_MEMORY;
 
 1081  callback->iface.OnDataReceived = video_data_on_data_received;
 
 1082  callback->iface.OnClose = video_data_on_close;
 
 1083  callback->plugin = listener_callback->plugin;
 
 1084  callback->channel_mgr = listener_callback->channel_mgr;
 
 1085  callback->channel = pChannel;
 
 1086  listener_callback->channel_callback = callback;
 
 1088  *ppCallback = (IWTSVirtualChannelCallback*)callback;
 
 1090  return CHANNEL_RC_OK;
 
 1093static uint64_t timer_cb(WINPR_ATTR_UNUSED rdpContext* context, 
void* userdata,
 
 1094                         WINPR_ATTR_UNUSED FreeRDP_TimerID timerID, uint64_t timestamp,
 
 1097  VideoClientContext* video = userdata;
 
 1103  video->timer(video, timestamp);
 
 1113static UINT video_plugin_initialize(IWTSPlugin* plugin, IWTSVirtualChannelManager* channelMgr)
 
 1116  VIDEO_PLUGIN* video = (VIDEO_PLUGIN*)plugin;
 
 1119  if (video->initialized)
 
 1121    WLog_ERR(TAG, 
"[%s] channel initialized twice, aborting", VIDEO_CONTROL_DVC_CHANNEL_NAME);
 
 1122    return ERROR_INVALID_DATA;
 
 1124  video->control_callback = callback =
 
 1128    WLog_ERR(TAG, 
"calloc for control callback failed!");
 
 1129    return CHANNEL_RC_NO_MEMORY;
 
 1132  callback->iface.OnNewChannelConnection = video_control_on_new_channel_connection;
 
 1133  callback->plugin = plugin;
 
 1134  callback->channel_mgr = channelMgr;
 
 1136  status = channelMgr->CreateListener(channelMgr, VIDEO_CONTROL_DVC_CHANNEL_NAME, 0,
 
 1137                                      &callback->iface, &(video->controlListener));
 
 1139  if (status != CHANNEL_RC_OK)
 
 1141  video->controlListener->pInterface = video->wtsPlugin.pInterface;
 
 1143  video->data_callback = callback =
 
 1147    WLog_ERR(TAG, 
"calloc for data callback failed!");
 
 1148    return CHANNEL_RC_NO_MEMORY;
 
 1151  callback->iface.OnNewChannelConnection = video_data_on_new_channel_connection;
 
 1152  callback->plugin = plugin;
 
 1153  callback->channel_mgr = channelMgr;
 
 1155  status = channelMgr->CreateListener(channelMgr, VIDEO_DATA_DVC_CHANNEL_NAME, 0,
 
 1156                                      &callback->iface, &(video->dataListener));
 
 1158  if (status == CHANNEL_RC_OK)
 
 1159    video->dataListener->pInterface = video->wtsPlugin.pInterface;
 
 1161  if (status == CHANNEL_RC_OK)
 
 1162    video->context->priv->timerID =
 
 1163        freerdp_timer_add(video->rdpcontext, 20000000, timer_cb, video->context, 
true);
 
 1164  video->initialized = video->context->priv->timerID != 0;
 
 1165  if (!video->initialized)
 
 1166    status = ERROR_INTERNAL_ERROR;
 
 1175static UINT video_plugin_terminated(IWTSPlugin* pPlugin)
 
 1177  VIDEO_PLUGIN* video = (VIDEO_PLUGIN*)pPlugin;
 
 1179    return CHANNEL_RC_INVALID_INSTANCE;
 
 1181  if (video->context && video->context->priv)
 
 1182    freerdp_timer_remove(video->rdpcontext, video->context->priv->timerID);
 
 1184  if (video->control_callback)
 
 1186    IWTSVirtualChannelManager* mgr = video->control_callback->channel_mgr;
 
 1188      IFCALL(mgr->DestroyListener, mgr, video->controlListener);
 
 1190  if (video->data_callback)
 
 1192    IWTSVirtualChannelManager* mgr = video->data_callback->channel_mgr;
 
 1194      IFCALL(mgr->DestroyListener, mgr, video->dataListener);
 
 1198    VideoClientContextPriv_free(video->context->priv);
 
 1200  free(video->control_callback);
 
 1201  free(video->data_callback);
 
 1202  free(video->wtsPlugin.pInterface);
 
 1204  return CHANNEL_RC_OK;
 
 1215FREERDP_ENTRY_POINT(UINT VCAPITYPE video_DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints))
 
 1217  UINT error = ERROR_INTERNAL_ERROR;
 
 1218  VIDEO_PLUGIN* videoPlugin = NULL;
 
 1219  VideoClientContext* videoContext = NULL;
 
 1220  VideoClientContextPriv* priv = NULL;
 
 1222  videoPlugin = (VIDEO_PLUGIN*)pEntryPoints->GetPlugin(pEntryPoints, 
"video");
 
 1225    videoPlugin = (VIDEO_PLUGIN*)calloc(1, 
sizeof(VIDEO_PLUGIN));
 
 1228      WLog_ERR(TAG, 
"calloc failed!");
 
 1229      return CHANNEL_RC_NO_MEMORY;
 
 1232    videoPlugin->wtsPlugin.Initialize = video_plugin_initialize;
 
 1233    videoPlugin->wtsPlugin.Connected = NULL;
 
 1234    videoPlugin->wtsPlugin.Disconnected = NULL;
 
 1235    videoPlugin->wtsPlugin.Terminated = video_plugin_terminated;
 
 1237    videoContext = (VideoClientContext*)calloc(1, 
sizeof(VideoClientContext));
 
 1240      WLog_ERR(TAG, 
"calloc failed!");
 
 1242      return CHANNEL_RC_NO_MEMORY;
 
 1245    priv = VideoClientContextPriv_new(videoContext);
 
 1248      WLog_ERR(TAG, 
"VideoClientContextPriv_new failed!");
 
 1251      return CHANNEL_RC_NO_MEMORY;
 
 1254    videoContext->handle = (
void*)videoPlugin;
 
 1255    videoContext->priv = priv;
 
 1256    videoContext->timer = video_timer;
 
 1257    videoContext->setGeometry = video_client_context_set_geometry;
 
 1259    videoPlugin->wtsPlugin.pInterface = (
void*)videoContext;
 
 1260    videoPlugin->context = videoContext;
 
 1261    videoPlugin->rdpcontext = pEntryPoints->GetRdpContext(pEntryPoints);
 
 1262    if (videoPlugin->rdpcontext)
 
 1263      error = pEntryPoints->RegisterPlugin(pEntryPoints, 
"video", &videoPlugin->wtsPlugin);
 
 1267    WLog_ERR(TAG, 
"could not get video Plugin.");
 
 1268    return CHANNEL_RC_BAD_CHANNEL;
 
a client to server notification struct
 
presentation request struct
 
response to a TSMM_PRESENTATION_REQUEST
 
an implementation of surface used by the video channel