Fix changelog email address
[freerdp-ubuntu-pcb-backport.git] / channels / drdynvc / tsmf / tsmf_media.c
1 /**
2  * FreeRDP: A Remote Desktop Protocol client.
3  * Video Redirection Virtual Channel - Media Container
4  *
5  * Copyright 2010-2011 Vic Lee
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *     http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <sys/time.h>
24 #include <freerdp/utils/memory.h>
25 #include <freerdp/utils/stream.h>
26 #include <freerdp/utils/list.h>
27 #include <freerdp/utils/thread.h>
28 #include <freerdp/utils/mutex.h>
29 #include <freerdp/utils/event.h>
30 #include <freerdp/utils/sleep.h>
31 #include <freerdp/plugins/tsmf.h>
32
33 #include "drdynvc_types.h"
34 #include "tsmf_constants.h"
35 #include "tsmf_types.h"
36 #include "tsmf_decoder.h"
37 #include "tsmf_audio.h"
38 #include "tsmf_main.h"
39 #include "tsmf_codec.h"
40 #include "tsmf_media.h"
41
42 #define AUDIO_TOLERANCE 10000000LL
43
44 struct _TSMF_PRESENTATION
45 {
46         uint8 presentation_id[GUID_SIZE];
47
48         const char* audio_name;
49         const char* audio_device;
50         int eos;
51
52         uint32 last_x;
53         uint32 last_y;
54         uint32 last_width;
55         uint32 last_height;
56         uint16 last_num_rects;
57         RDP_RECT* last_rects;
58
59         uint32 output_x;
60         uint32 output_y;
61         uint32 output_width;
62         uint32 output_height;
63         uint16 output_num_rects;
64         RDP_RECT* output_rects;
65
66         IWTSVirtualChannelCallback* channel_callback;
67
68         uint64 audio_start_time;
69         uint64 audio_end_time;
70
71         /* The stream list could be accessed by differnt threads and need to be protected. */
72         freerdp_mutex mutex;
73
74         LIST* stream_list;
75 };
76
77 struct _TSMF_STREAM
78 {
79         uint32 stream_id;
80
81         TSMF_PRESENTATION* presentation;
82
83         ITSMFDecoder* decoder;
84
85         int major_type;
86         int eos;
87         uint32 width;
88         uint32 height;
89
90         ITSMFAudioDevice* audio;
91         uint32 sample_rate;
92         uint32 channels;
93         uint32 bits_per_sample;
94
95         /* The end_time of last played sample */
96         uint64 last_end_time;
97         /* Next sample should not start before this system time. */
98         uint64 next_start_time;
99
100         freerdp_thread* thread;
101
102         LIST* sample_list;
103
104         /* The sample ack response queue will be accessed only by the stream thread. */
105         LIST* sample_ack_list;
106 };
107
108 struct _TSMF_SAMPLE
109 {
110         uint32 sample_id;
111         uint64 start_time;
112         uint64 end_time;
113         uint64 duration;
114         uint32 extensions;
115         uint32 data_size;
116         uint8* data;
117         uint32 decoded_size;
118         uint32 pixfmt;
119
120         TSMF_STREAM* stream;
121         IWTSVirtualChannelCallback* channel_callback;
122         uint64 ack_time;
123 };
124
125 static LIST* presentation_list = NULL;
126
127 static uint64 get_current_time(void)
128 {
129         struct timeval tp;
130
131         gettimeofday(&tp, 0);
132         return ((uint64)tp.tv_sec) * 10000000LL + ((uint64)tp.tv_usec) * 10LL;
133 }
134
135 static TSMF_SAMPLE* tsmf_stream_pop_sample(TSMF_STREAM* stream, int sync)
136 {
137         TSMF_STREAM* s;
138         LIST_ITEM* item;
139         TSMF_SAMPLE* sample;
140         boolean pending = false;
141         TSMF_PRESENTATION* presentation = stream->presentation;
142
143         if (!stream->sample_list->head)
144                 return NULL;
145
146         if (sync)
147         {
148                 if (stream->major_type == TSMF_MAJOR_TYPE_AUDIO)
149                 {
150                         /* Check if some other stream has earlier sample that needs to be played first */
151                         if (stream->last_end_time > AUDIO_TOLERANCE)
152                         {
153                                 freerdp_mutex_lock(presentation->mutex);
154                                 for (item = presentation->stream_list->head; item; item = item->next)
155                                 {
156                                         s = (TSMF_STREAM*) item->data;
157                                         if (s != stream && !s->eos && s->last_end_time &&
158                                                 s->last_end_time < stream->last_end_time - AUDIO_TOLERANCE)
159                                         {
160                                                         pending = true;
161                                                         break;
162                                         }
163                                 }
164                                 freerdp_mutex_unlock(presentation->mutex);
165                         }
166                 }
167                 else
168                 {
169                         if (stream->last_end_time > presentation->audio_end_time)
170                         {
171                                 pending = true;
172                         }
173                 }
174         }
175         if (pending)
176                 return NULL;
177
178         freerdp_thread_lock(stream->thread);
179         sample = (TSMF_SAMPLE*) list_dequeue(stream->sample_list);
180         freerdp_thread_unlock(stream->thread);
181
182         if (sample && sample->end_time > stream->last_end_time)
183                 stream->last_end_time = sample->end_time;
184
185         return sample;
186 }
187
188 static void tsmf_sample_free(TSMF_SAMPLE* sample)
189 {
190         if (sample->data)
191                 xfree(sample->data);
192         xfree(sample);
193 }
194
195 static void tsmf_sample_ack(TSMF_SAMPLE* sample)
196 {
197         tsmf_playback_ack(sample->channel_callback, sample->sample_id, sample->duration, sample->data_size);
198 }
199
200 static void tsmf_sample_queue_ack(TSMF_SAMPLE* sample)
201 {
202         TSMF_STREAM* stream = sample->stream;
203
204         list_enqueue(stream->sample_ack_list, sample);
205 }
206
207 static void tsmf_stream_process_ack(TSMF_STREAM* stream)
208 {
209         TSMF_SAMPLE* sample;
210         uint64 ack_time;
211
212         ack_time = get_current_time();
213         while (stream->sample_ack_list->head && !freerdp_thread_is_stopped(stream->thread))
214         {
215                 sample = (TSMF_SAMPLE*) list_peek(stream->sample_ack_list);
216                 if (sample->ack_time > ack_time)
217                         break;
218
219                 sample = list_dequeue(stream->sample_ack_list);
220                 tsmf_sample_ack(sample);
221                 tsmf_sample_free(sample);
222         }
223 }
224
225 TSMF_PRESENTATION* tsmf_presentation_new(const uint8* guid, IWTSVirtualChannelCallback* pChannelCallback)
226 {
227         TSMF_PRESENTATION* presentation;
228
229         presentation = tsmf_presentation_find_by_id(guid);
230         if (presentation)
231         {
232                 DEBUG_WARN("duplicated presentation id!");
233                 return NULL;
234         }
235
236         presentation = xnew(TSMF_PRESENTATION);
237
238         memcpy(presentation->presentation_id, guid, GUID_SIZE);
239         presentation->channel_callback = pChannelCallback;
240
241         presentation->mutex = freerdp_mutex_new();
242         presentation->stream_list = list_new();
243
244         list_enqueue(presentation_list, presentation);
245
246         return presentation;
247 }
248
249 TSMF_PRESENTATION* tsmf_presentation_find_by_id(const uint8* guid)
250 {
251         LIST_ITEM* item;
252         TSMF_PRESENTATION* presentation;
253
254         for (item = presentation_list->head; item; item = item->next)
255         {
256                 presentation = (TSMF_PRESENTATION*) item->data;
257                 if (memcmp(presentation->presentation_id, guid, GUID_SIZE) == 0)
258                         return presentation;
259         }
260         return NULL;
261 }
262
263 static void tsmf_presentation_restore_last_video_frame(TSMF_PRESENTATION* presentation)
264 {
265         RDP_REDRAW_EVENT* revent;
266
267         if (presentation->last_width && presentation->last_height)
268         {
269                 revent = (RDP_REDRAW_EVENT*) freerdp_event_new(RDP_EVENT_CLASS_TSMF, RDP_EVENT_TYPE_TSMF_REDRAW,
270                         NULL, NULL);
271                 revent->x = presentation->last_x;
272                 revent->y = presentation->last_y;
273                 revent->width = presentation->last_width;
274                 revent->height = presentation->last_height;
275                 if (!tsmf_push_event(presentation->channel_callback, (RDP_EVENT*) revent))
276                 {
277                         freerdp_event_free((RDP_EVENT*) revent);
278                 }
279                 presentation->last_x = 0;
280                 presentation->last_y = 0;
281                 presentation->last_width = 0;
282                 presentation->last_height = 0;
283         }
284 }
285
286 static void tsmf_sample_playback_video(TSMF_SAMPLE* sample)
287 {
288         uint64 t;
289         RDP_VIDEO_FRAME_EVENT* vevent;
290         TSMF_STREAM* stream = sample->stream;
291         TSMF_PRESENTATION* presentation = stream->presentation;
292
293         DEBUG_DVC("MessageId %d EndTime %d data_size %d consumed.",
294                 sample->sample_id, (int)sample->end_time, sample->data_size);
295
296         if (sample->data)
297         {
298                 t = get_current_time();
299                 if (stream->next_start_time > t &&
300                         (sample->end_time >= presentation->audio_start_time ||
301                         sample->end_time < stream->last_end_time))
302                 {
303                         freerdp_usleep((stream->next_start_time - t) / 10);
304                 }
305                 stream->next_start_time = t + sample->duration - 50000;
306
307                 if (presentation->last_x != presentation->output_x ||
308                         presentation->last_y != presentation->output_y ||
309                         presentation->last_width != presentation->output_width ||
310                         presentation->last_height != presentation->output_height ||
311                         presentation->last_num_rects != presentation->output_num_rects ||
312                         (presentation->last_rects && presentation->output_rects &&
313                         memcmp(presentation->last_rects, presentation->output_rects,
314                         presentation->last_num_rects * sizeof(RDP_RECT)) != 0))
315                 {
316                         tsmf_presentation_restore_last_video_frame(presentation);
317
318                         presentation->last_x = presentation->output_x;
319                         presentation->last_y = presentation->output_y;
320                         presentation->last_width = presentation->output_width;
321                         presentation->last_height = presentation->output_height;
322
323                         if (presentation->last_rects)
324                         {
325                                 xfree(presentation->last_rects);
326                                 presentation->last_rects = NULL;
327                         }
328                         presentation->last_num_rects = presentation->output_num_rects;
329                         if (presentation->last_num_rects > 0)
330                         {
331                                 presentation->last_rects = xzalloc(presentation->last_num_rects * sizeof(RDP_RECT));
332                                 memcpy(presentation->last_rects, presentation->output_rects,
333                                         presentation->last_num_rects * sizeof(RDP_RECT));
334                         }
335                 }
336
337                 vevent = (RDP_VIDEO_FRAME_EVENT*) freerdp_event_new(RDP_EVENT_CLASS_TSMF, RDP_EVENT_TYPE_TSMF_VIDEO_FRAME,
338                         NULL, NULL);
339                 vevent->frame_data = sample->data;
340                 vevent->frame_size = sample->decoded_size;
341                 vevent->frame_pixfmt = sample->pixfmt;
342                 vevent->frame_width = sample->stream->width;
343                 vevent->frame_height = sample->stream->height;
344                 vevent->x = presentation->output_x;
345                 vevent->y = presentation->output_y;
346                 vevent->width = presentation->output_width;
347                 vevent->height = presentation->output_height;
348                 if (presentation->output_num_rects > 0)
349                 {
350                         vevent->num_visible_rects = presentation->output_num_rects;
351                         vevent->visible_rects = (RDP_RECT*) xzalloc(presentation->output_num_rects * sizeof(RDP_RECT));
352                         memcpy(vevent->visible_rects, presentation->output_rects,
353                                 presentation->output_num_rects * sizeof(RDP_RECT));
354                 }
355
356                 /* The frame data ownership is passed to the event object, and is freed after the event is processed. */
357                 sample->data = NULL;
358                 sample->decoded_size = 0;
359
360                 if (!tsmf_push_event(sample->channel_callback, (RDP_EVENT*) vevent))
361                 {
362                         freerdp_event_free((RDP_EVENT*) vevent);
363                 }
364
365 #if 0
366                 /* Dump a .ppm image for every 30 frames. Assuming the frame is in YUV format, we
367                    extract the Y values to create a grayscale image. */
368                 static int frame_id = 0;
369                 char buf[100];
370                 FILE * fp;
371                 if ((frame_id % 30) == 0)
372                 {
373                         snprintf(buf, sizeof(buf), "/tmp/FreeRDP_Frame_%d.ppm", frame_id);
374                         fp = fopen(buf, "wb");
375                         fwrite("P5\n", 1, 3, fp);
376                         snprintf(buf, sizeof(buf), "%d %d\n", sample->stream->width, sample->stream->height);
377                         fwrite(buf, 1, strlen(buf), fp);
378                         fwrite("255\n", 1, 4, fp);
379                         fwrite(sample->data, 1, sample->stream->width * sample->stream->height, fp);
380                         fflush(fp);
381                         fclose(fp);
382                 }
383                 frame_id++;
384 #endif
385         }
386 }
387
388 static void tsmf_sample_playback_audio(TSMF_SAMPLE* sample)
389 {
390         uint64 latency = 0;
391         TSMF_STREAM* stream = sample->stream;
392
393         DEBUG_DVC("MessageId %d EndTime %d consumed.",
394                 sample->sample_id, (int)sample->end_time);
395
396         if (sample->stream->audio && sample->data)
397         {
398                 sample->stream->audio->Play(sample->stream->audio,
399                         sample->data, sample->decoded_size);
400                 sample->data = NULL;
401                 sample->decoded_size = 0;
402
403                 if (stream->audio && stream->audio->GetLatency)
404                         latency = stream->audio->GetLatency(stream->audio);
405         }
406         else
407         {
408                 latency = 0;
409         }
410
411         sample->ack_time = latency + get_current_time();
412         stream->last_end_time = sample->end_time + latency;
413         stream->presentation->audio_start_time = sample->start_time + latency;
414         stream->presentation->audio_end_time = sample->end_time + latency;
415 }
416
417 static void tsmf_sample_playback(TSMF_SAMPLE* sample)
418 {
419         boolean ret = false;
420         uint32 width;
421         uint32 height;
422         uint32 pixfmt = 0;
423         TSMF_STREAM* stream = sample->stream;
424
425         if (stream->decoder)
426                 ret = stream->decoder->Decode(stream->decoder, sample->data, sample->data_size, sample->extensions);
427         if (!ret)
428         {
429                 tsmf_sample_ack(sample);
430                 tsmf_sample_free(sample);
431                 return;
432         }
433
434         xfree(sample->data);
435         sample->data = NULL;
436
437         if (stream->major_type == TSMF_MAJOR_TYPE_VIDEO)
438         {
439                 if (stream->decoder->GetDecodedFormat)
440                 {
441                         pixfmt = stream->decoder->GetDecodedFormat(stream->decoder);
442                         if (pixfmt == ((uint32) -1))
443                         {
444                                 tsmf_sample_ack(sample);
445                                 tsmf_sample_free(sample);
446                                 return;
447                         }
448                         sample->pixfmt = pixfmt;
449                 }
450
451                 if (stream->decoder->GetDecodedDimension)
452                         ret = stream->decoder->GetDecodedDimension(stream->decoder, &width, &height);
453                 if (ret && (width != stream->width || height != stream->height))
454                 {
455                         DEBUG_DVC("video dimension changed to %d x %d", width, height);
456                         stream->width = width;
457                         stream->height = height;
458                 }
459         }
460
461         if (stream->decoder->GetDecodedData)
462         {
463                 sample->data = stream->decoder->GetDecodedData(stream->decoder, &sample->decoded_size);
464         }
465
466         switch (sample->stream->major_type)
467         {
468                 case TSMF_MAJOR_TYPE_VIDEO:
469                         tsmf_sample_playback_video(sample);
470                         tsmf_sample_ack(sample);
471                         tsmf_sample_free(sample);
472                         break;
473                 case TSMF_MAJOR_TYPE_AUDIO:
474                         tsmf_sample_playback_audio(sample);
475                         tsmf_sample_queue_ack(sample);
476                         break;
477         }
478 }
479
480 static void* tsmf_stream_playback_func(void* arg)
481 {
482         TSMF_SAMPLE* sample;
483         TSMF_STREAM* stream = (TSMF_STREAM*) arg;
484         TSMF_PRESENTATION* presentation = stream->presentation;
485
486         DEBUG_DVC("in %d", stream->stream_id);
487
488         if (stream->major_type == TSMF_MAJOR_TYPE_AUDIO &&
489                 stream->sample_rate && stream->channels && stream->bits_per_sample)
490         {
491                 stream->audio = tsmf_load_audio_device(
492                         presentation->audio_name && presentation->audio_name[0] ? presentation->audio_name : NULL,
493                         presentation->audio_device && presentation->audio_device[0] ? presentation->audio_device : NULL);
494                 if (stream->audio)
495                 {
496                         stream->audio->SetFormat(stream->audio,
497                                 stream->sample_rate, stream->channels, stream->bits_per_sample);
498                 }
499         }
500         while (!freerdp_thread_is_stopped(stream->thread))
501         {
502                 tsmf_stream_process_ack(stream);
503                 sample = tsmf_stream_pop_sample(stream, 1);
504                 if (sample)
505                         tsmf_sample_playback(sample);
506                 else
507                         freerdp_usleep(5000);
508         }
509         if (stream->eos || presentation->eos)
510         {
511                 while ((sample = tsmf_stream_pop_sample(stream, 1)) != NULL)
512                         tsmf_sample_playback(sample);
513         }
514         if (stream->audio)
515         {
516                 stream->audio->Free(stream->audio);
517                 stream->audio = NULL;
518         }
519
520         freerdp_thread_quit(stream->thread);
521
522         DEBUG_DVC("out %d", stream->stream_id);
523
524         return NULL;
525 }
526
527 static void tsmf_stream_start(TSMF_STREAM* stream)
528 {
529         if (!freerdp_thread_is_running(stream->thread))
530         {
531                 freerdp_thread_start(stream->thread, tsmf_stream_playback_func, stream);
532         }
533 }
534
535 static void tsmf_stream_stop(TSMF_STREAM* stream)
536 {
537         if (freerdp_thread_is_running(stream->thread))
538         {
539                 freerdp_thread_stop(stream->thread);
540         }
541 }
542
543 void tsmf_presentation_start(TSMF_PRESENTATION* presentation)
544 {
545         LIST_ITEM* item;
546         TSMF_STREAM* stream;
547
548         for (item = presentation->stream_list->head; item; item = item->next)
549         {
550                 stream = (TSMF_STREAM*) item->data;
551                 tsmf_stream_start(stream);
552         }
553 }
554
555 void tsmf_presentation_stop(TSMF_PRESENTATION* presentation)
556 {
557         LIST_ITEM* item;
558         TSMF_STREAM* stream;
559
560         tsmf_presentation_flush(presentation);
561
562         for (item = presentation->stream_list->head; item; item = item->next)
563         {
564                 stream = (TSMF_STREAM*) item->data;
565                 tsmf_stream_stop(stream);
566         }
567
568         tsmf_presentation_restore_last_video_frame(presentation);
569         if (presentation->last_rects)
570         {
571                 xfree(presentation->last_rects);
572                 presentation->last_rects = NULL;
573         }
574         presentation->last_num_rects = 0;
575         if (presentation->output_rects)
576         {
577                 xfree(presentation->output_rects);
578                 presentation->output_rects = NULL;
579         }
580         presentation->output_num_rects = 0;
581 }
582
583 void tsmf_presentation_set_geometry_info(TSMF_PRESENTATION* presentation,
584         uint32 x, uint32 y, uint32 width, uint32 height,
585         int num_rects, RDP_RECT* rects)
586 {
587         presentation->output_x = x;
588         presentation->output_y = y;
589         presentation->output_width = width;
590         presentation->output_height = height;
591         if (presentation->output_rects)
592                 xfree(presentation->output_rects);
593         presentation->output_rects = rects;
594         presentation->output_num_rects = num_rects;
595 }
596
597 void tsmf_presentation_set_audio_device(TSMF_PRESENTATION* presentation, const char* name, const char* device)
598 {
599         presentation->audio_name = name;
600         presentation->audio_device = device;
601 }
602
603 static void tsmf_stream_flush(TSMF_STREAM* stream)
604 {
605         TSMF_SAMPLE* sample;
606
607         while ((sample = tsmf_stream_pop_sample(stream, 0)) != NULL)
608                 tsmf_sample_free(sample);
609
610         while ((sample = list_dequeue(stream->sample_ack_list)) != NULL)
611                 tsmf_sample_free(sample);
612
613         if (stream->audio)
614                 stream->audio->Flush(stream->audio);
615
616         stream->eos = 0;
617         stream->last_end_time = 0;
618         stream->next_start_time = 0;
619         if (stream->major_type == TSMF_MAJOR_TYPE_AUDIO)
620         {
621                 stream->presentation->audio_start_time = 0;
622                 stream->presentation->audio_end_time = 0;
623         }
624 }
625
626 void tsmf_presentation_flush(TSMF_PRESENTATION* presentation)
627 {
628         LIST_ITEM* item;
629         TSMF_STREAM * stream;
630
631         for (item = presentation->stream_list->head; item; item = item->next)
632         {
633                 stream = (TSMF_STREAM*) item->data;
634                 tsmf_stream_flush(stream);
635         }
636
637         presentation->eos = 0;
638         presentation->audio_start_time = 0;
639         presentation->audio_end_time = 0;
640 }
641
642 void tsmf_presentation_free(TSMF_PRESENTATION* presentation)
643 {
644         TSMF_STREAM* stream;
645
646         tsmf_presentation_stop(presentation);
647         list_remove(presentation_list, presentation);
648
649         while (presentation->stream_list->head)
650         {
651                 stream = (TSMF_STREAM*) list_peek(presentation->stream_list);
652                 tsmf_stream_free(stream);
653         }
654         list_free(presentation->stream_list);
655
656         freerdp_mutex_free(presentation->mutex);
657
658         xfree(presentation);
659 }
660
661 TSMF_STREAM* tsmf_stream_new(TSMF_PRESENTATION* presentation, uint32 stream_id)
662 {
663         TSMF_STREAM* stream;
664
665         stream = tsmf_stream_find_by_id(presentation, stream_id);
666         if (stream)
667         {
668                 DEBUG_WARN("duplicated stream id %d!", stream_id);
669                 return NULL;
670         }
671
672         stream = xnew(TSMF_STREAM);
673
674         stream->stream_id = stream_id;
675         stream->presentation = presentation;
676         stream->thread = freerdp_thread_new();
677         stream->sample_list = list_new();
678         stream->sample_ack_list = list_new();
679
680         freerdp_mutex_lock(presentation->mutex);
681         list_enqueue(presentation->stream_list, stream);
682         freerdp_mutex_unlock(presentation->mutex);
683
684         return stream;
685 }
686
687 TSMF_STREAM* tsmf_stream_find_by_id(TSMF_PRESENTATION* presentation, uint32 stream_id)
688 {
689         LIST_ITEM* item;
690         TSMF_STREAM* stream;
691
692         for (item = presentation->stream_list->head; item; item = item->next)
693         {
694                 stream = (TSMF_STREAM*) item->data;
695                 if (stream->stream_id == stream_id)
696                         return stream;
697         }
698         return NULL;
699 }
700
701 void tsmf_stream_set_format(TSMF_STREAM* stream, const char* name, STREAM* s)
702 {
703         TS_AM_MEDIA_TYPE mediatype;
704
705         if (stream->decoder)
706         {
707                 DEBUG_WARN("duplicated call");
708                 return;
709         }
710
711         tsmf_codec_parse_media_type(&mediatype, s);
712
713         if (mediatype.MajorType == TSMF_MAJOR_TYPE_VIDEO)
714         {
715                 DEBUG_DVC("video width %d height %d bit_rate %d frame_rate %f codec_data %d",
716                         mediatype.Width, mediatype.Height, mediatype.BitRate,
717                         (double)mediatype.SamplesPerSecond.Numerator / (double)mediatype.SamplesPerSecond.Denominator,
718                         mediatype.ExtraDataSize);
719         }
720         else if (mediatype.MajorType == TSMF_MAJOR_TYPE_AUDIO)
721         {
722                 DEBUG_DVC("audio channel %d sample_rate %d bits_per_sample %d codec_data %d",
723                         mediatype.Channels, mediatype.SamplesPerSecond.Numerator, mediatype.BitsPerSample,
724                         mediatype.ExtraDataSize);
725                 stream->sample_rate = mediatype.SamplesPerSecond.Numerator;
726                 stream->channels = mediatype.Channels;
727                 stream->bits_per_sample = mediatype.BitsPerSample;
728                 if (stream->bits_per_sample == 0)
729                         stream->bits_per_sample = 16;
730         }
731
732         stream->major_type = mediatype.MajorType;
733         stream->width = mediatype.Width;
734         stream->height = mediatype.Height;
735         stream->decoder = tsmf_load_decoder(name, &mediatype);
736 }
737
738 void tsmf_stream_end(TSMF_STREAM* stream)
739 {
740         stream->eos = 1;
741         stream->presentation->eos = 1;
742 }
743
744 void tsmf_stream_free(TSMF_STREAM* stream)
745 {
746         TSMF_PRESENTATION* presentation = stream->presentation;
747
748         tsmf_stream_stop(stream);
749         tsmf_stream_flush(stream);
750
751         freerdp_mutex_lock(presentation->mutex);
752         list_remove(presentation->stream_list, stream);
753         freerdp_mutex_unlock(presentation->mutex);
754
755         list_free(stream->sample_list);
756         list_free(stream->sample_ack_list);
757
758         if (stream->decoder)
759                 stream->decoder->Free(stream->decoder);
760
761         freerdp_thread_free(stream->thread);
762
763         xfree(stream);
764 }
765
766 void tsmf_stream_push_sample(TSMF_STREAM* stream, IWTSVirtualChannelCallback* pChannelCallback,
767         uint32 sample_id, uint64 start_time, uint64 end_time, uint64 duration, uint32 extensions,
768         uint32 data_size, uint8* data)
769 {
770         TSMF_SAMPLE* sample;
771
772         sample = xnew(TSMF_SAMPLE);
773
774         sample->sample_id = sample_id;
775         sample->start_time = start_time;
776         sample->end_time = end_time;
777         sample->duration = duration;
778         sample->extensions = extensions;
779         sample->stream = stream;
780         sample->channel_callback = pChannelCallback;
781         sample->data_size = data_size;
782         sample->data = xzalloc(data_size + TSMF_BUFFER_PADDING_SIZE);
783         memcpy(sample->data, data, data_size);
784
785         freerdp_thread_lock(stream->thread);
786         list_enqueue(stream->sample_list, sample);
787         freerdp_thread_unlock(stream->thread);
788 }
789
790 void tsmf_media_init(void)
791 {
792         if (presentation_list == NULL)
793                 presentation_list = list_new();
794 }
795