1
2 #include <stdint.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <ctype.h>
6
7 #include <SDL2/SDL.h>
8 #ifndef _POSIX_SOURCE
9 #define __USE_POSIX199309 (1) // make posix GCC workable
10 #define __USE_XOPEN2K
11 #endif
12 #include <pthread.h>
13 #ifdef _TIMESPEC_DEFINED // make MinGW workable
14 #include <pthread_time.h>
15 #endif
16
17 #include "tiny_codec.h"
18 #include "stream_codec.h"
19
stream_codec_init(stream_codec_p s)20 void stream_codec_init(stream_codec_p s)
21 {
22 s->state = VIDEO_STATE_STOPPED;
23 s->stop = 0;
24 s->update_audio = 1;
25 s->thread = 0;
26 pthread_mutex_init(&s->timer_mutex, NULL);
27 pthread_mutex_init(&s->video_buffer_mutex, NULL);
28 pthread_mutex_init(&s->audio_buffer_mutex, NULL);
29 codec_init(&s->codec, NULL);
30 }
31
32
stream_codec_clear(stream_codec_p s)33 void stream_codec_clear(stream_codec_p s)
34 {
35 s->stop = 1;
36 if(s->thread)
37 {
38 pthread_join(s->thread, NULL);
39 s->thread = 0;
40 }
41
42 pthread_mutex_destroy(&s->timer_mutex);
43 pthread_mutex_destroy(&s->video_buffer_mutex);
44 pthread_mutex_destroy(&s->audio_buffer_mutex);
45 }
46
47
stream_codec_check_end(stream_codec_p s)48 int stream_codec_check_end(stream_codec_p s)
49 {
50 if(s->state == VIDEO_STATE_STOPPED)
51 {
52 if(s->thread)
53 {
54 pthread_join(s->thread, NULL);
55 s->thread = 0;
56 return 1;
57 }
58 return 0;
59 }
60 return -1;
61 }
62
63
stream_codec_stop(stream_codec_p s,int wait)64 void stream_codec_stop(stream_codec_p s, int wait)
65 {
66 s->stop = 1;
67 if(wait && s->thread)
68 {
69 pthread_join(s->thread, NULL);
70 s->thread = 0;
71 }
72 }
73
74
stream_codec_thread_func(void * data)75 static void *stream_codec_thread_func(void *data)
76 {
77 stream_codec_p s = (stream_codec_p)data;
78 if(s)
79 {
80 uint64_t frame = 0;
81 uint64_t ns = 0;
82 struct timespec time_start = { 0 };
83 struct timespec vid_time;
84 int can_continue = 1;
85
86 clock_gettime(CLOCK_REALTIME, &time_start);
87
88 while(!s->stop && can_continue)
89 {
90 frame++;
91 can_continue = 0;
92 ns = (frame * s->codec.fps_denum) % s->codec.fps_num;
93 ns = ns * 1000000000 / s->codec.fps_num;
94 vid_time.tv_sec = time_start.tv_sec + frame * s->codec.fps_denum / s->codec.fps_num;
95 vid_time.tv_nsec = time_start.tv_nsec + ns;
96 if(vid_time.tv_nsec >= 1000000000)
97 {
98 vid_time.tv_nsec -= 1000000000;
99 vid_time.tv_sec++;
100 }
101
102 if(s->update_audio && s->codec.audio.decode && (s->codec.packet(&s->codec, &s->codec.audio.pkt) >= 0))
103 {
104 pthread_mutex_lock(&s->audio_buffer_mutex);
105 s->codec.audio.decode(&s->codec, &s->codec.audio.pkt);
106 s->update_audio = 0;
107 pthread_mutex_unlock(&s->audio_buffer_mutex);
108 }
109
110 if(s->codec.video.decode && (s->codec.packet(&s->codec, &s->codec.video.pkt) >= 0))
111 {
112 pthread_mutex_lock(&s->video_buffer_mutex);
113 s->codec.video.decode(&s->codec, &s->codec.video.pkt);
114 pthread_mutex_unlock(&s->video_buffer_mutex);
115 can_continue++;
116 }
117
118 s->state = VIDEO_STATE_RUNNING;
119 pthread_mutex_timedlock(&s->timer_mutex, &vid_time);
120 }
121 s->state = VIDEO_STATE_QEUED;
122
123 pthread_mutex_lock(&s->video_buffer_mutex);
124 pthread_mutex_lock(&s->audio_buffer_mutex);
125 codec_clear(&s->codec);
126 pthread_mutex_unlock(&s->audio_buffer_mutex);
127 pthread_mutex_unlock(&s->video_buffer_mutex);
128
129 SDL_RWclose(s->codec.input);
130 s->codec.input = NULL;
131 }
132 s->state = VIDEO_STATE_STOPPED;
133
134 return NULL;
135 }
136
137
stream_codec_video_lock(stream_codec_p s)138 void stream_codec_video_lock(stream_codec_p s)
139 {
140 pthread_mutex_lock(&s->video_buffer_mutex);
141 }
142
143
stream_codec_video_unlock(stream_codec_p s)144 void stream_codec_video_unlock(stream_codec_p s)
145 {
146 pthread_mutex_unlock(&s->video_buffer_mutex);
147 }
148
149
stream_codec_audio_lock(stream_codec_p s)150 void stream_codec_audio_lock(stream_codec_p s)
151 {
152 pthread_mutex_lock(&s->audio_buffer_mutex);
153 }
154
155
stream_codec_audio_unlock(stream_codec_p s)156 void stream_codec_audio_unlock(stream_codec_p s)
157 {
158 pthread_mutex_unlock(&s->audio_buffer_mutex);
159 }
160
161
stream_codec_play(stream_codec_p s)162 int stream_codec_play(stream_codec_p s)
163 {
164 if((s->state == VIDEO_STATE_STOPPED) && s->codec.input)
165 {
166 s->state = VIDEO_STATE_QEUED;
167 s->stop = 0;
168 return 0 != pthread_create(&s->thread, NULL, stream_codec_thread_func, s);
169 }
170 return 0;
171 }