]> rtime.felk.cvut.cz Git - frescor/streamer.git/blob - streamer.c
3f0646cc94984e2611932a70d000f015caeb40f2
[frescor/streamer.git] / streamer.c
1 /*
2  *  Copyright (c) 2008 Luca Abeni
3  *
4  *  This is free software; see GPL.txt
5  */
6 #include <unistd.h>
7 #include <stdlib.h>
8 #include <signal.h>
9 #include <pthread.h>
10
11 #include <libavformat/avformat.h>
12 #include <libavdevice/avdevice.h>
13 #include <libswscale/swscale.h>
14
15 #include "input.h"
16 #include "output.h"
17 #include "codec.h"
18 #include "rt.h"
19
20 #include "streamer_config.h"
21
22 #ifdef CONFIG_OC_ULUT
23 #include <ul_log.h>
24 #include <ul_logreg.h>
25 #endif
26
27 #ifdef CONFIG_FFMPEG_WITH_FRSH
28 #include <frsh.h>
29
30 /*temporrary solution to pass network parameters */
31 extern long int avformat_frsh_budget, avformat_frsh_period;
32 #endif /*CONFIG_STREAMER_WITH_FRSH*/
33
34 static const char *sdp_file = "sdp.txt";
35 static const char *vdev = "/dev/video0";
36 static const char *dst = "127.0.0.1";
37 static int dport = 20000;
38 static int width = 320;
39 static int height = 240;
40 int fps = 15;
41 static const char *impform = "video4linux2";
42 AVFormatContext *s, *os;
43
44 static void sdp_print(AVFormatContext *s, const char *fname)
45 {
46     char sdp[2048];
47     FILE *f;
48
49     f = fopen(fname, "w");
50     avf_sdp_create(&s, 1, sdp, sizeof(sdp));
51     fprintf(f, "%s\n", sdp);
52     fclose(f);
53 }
54
55 static void
56 usage(void)
57 {
58         printf("usage: streamer [ options ]\n");
59         printf("  -w <number>    send image width\n");
60         printf("  -h <number>    send image height\n");
61         printf("  -r <number>    refresh rate\n");
62         printf("  -r <path>      video device [%s]\n", vdev);
63         printf("  -m <addr>      destination IP address\n");
64         printf("  -i <string>    input video device format [%s]\n", impform);
65         printf("  -o <pOrt>      destination port [%d]\n", dport);
66       #ifdef CONFIG_STREAMER_WITH_FRSH
67         printf("  -b <number>    network budget\n");
68         printf("  -p <number>    network period for given budget\n");
69       #endif /*CONFIG_STREAMER_WITH_FRSH*/
70       #ifdef CONFIG_OC_ULUT
71         printf("  -l <number>|<domain>=<number>,...\n");
72       #endif /*CONFIG_OC_ULUT*/
73 }
74
75 static int args_parse(int argc, char *argv[])
76 {
77   int v;
78
79   while ((v = getopt(argc, argv, "o:w:h:r:d:m:i:l:b:p:")) >= 0) {
80     switch (v) {
81       case 'o':
82         dport = atoi(optarg);
83         break;
84       case 'w':
85         width = atoi(optarg);
86         break;
87       case 'h':
88         height = atoi(optarg);
89         break;
90       case 'r':
91         fps = atoi(optarg);
92         break;
93       case 'd':
94         vdev = optarg;
95         break;
96       case 'm':
97         dst = optarg;
98         break;
99       case 'i':
100         impform = optarg;
101         if(!strcmp(impform, "v4l"))
102           impform = "video4linux";
103         else if(!strcmp(impform, "v4l2"))
104           impform = "video4linux2";
105         break;
106       #ifdef CONFIG_STREAMER_WITH_FRSH
107       case 'b':
108         udp_budget = atol(optarg);
109         break;
110       case 'p':
111         udp_period = atol(optarg);
112         break;
113       #endif /*CONFIG_STREAMER_WITH_FRSH*/
114
115       #ifdef CONFIG_OC_ULUT
116       case 'l':
117         ul_log_domain_arg2levels(optarg);
118         break;
119       #endif /*CONFIG_OC_ULUT*/
120
121       default: /* unknown option */
122         fprintf(stderr, "%s: illegal option %c\n", argv[0], v);
123         usage();
124         exit(-1);
125     }
126   }
127
128   return 0;
129 }
130
131 int streamer_run_done_rq;
132
133 int
134 timespec_subtract (struct timespec *result,
135                    struct timespec *x,
136                    struct timespec *y)
137 {
138   /* Perform the carry for the later subtraction by updating Y. */
139   if (x->tv_nsec < y->tv_nsec) {
140     int num_sec = (y->tv_nsec - x->tv_nsec) / 1000000000 + 1;
141     y->tv_nsec -= 1000000000 * num_sec;
142     y->tv_sec += num_sec;
143   }
144   if (x->tv_nsec - y->tv_nsec > 1000000000) {
145     int num_sec = (x->tv_nsec - y->tv_nsec) / 1000000000;
146     y->tv_nsec += 1000000000 * num_sec;
147     y->tv_sec -= num_sec;
148   }
149
150   /* Compute the time remaining to wait.
151      `tv_nsec' is certainly positive. */
152   result->tv_sec = x->tv_sec - y->tv_sec;
153   result->tv_nsec = x->tv_nsec - y->tv_nsec;
154
155   /* Return 1 if result is negative. */
156   return x->tv_sec < y->tv_sec;
157 }
158
159
160 void* streamer_run(void* args)
161 {
162   int done;
163   int frame = 0;
164   int fps_avg = 0;
165   struct timespec start, end, d;
166   static unsigned max_size = 0, min_size = -1;
167   static double avg_size = 0;
168   clock_gettime(CLOCK_MONOTONIC, &start);
169   done = 0;
170   while (!(done = streamer_run_done_rq)) {
171     AVPacket *pkt;
172     pkt = read_input_packet(s);
173     if (pkt == NULL) {
174       done = 1;
175     } else {
176       AVFrame *f;
177       AVPacket *opkt;
178
179       pkt->pts += s->streams[pkt->stream_index]->start_time;
180       //rt_job_start(pkt->pts);
181       f = pkt_decode(s, pkt);
182       if (f) {
183         opkt = pkt_encode(os, f);
184         if (opkt) {
185           pkt_send(os, opkt);
186
187           clock_gettime(CLOCK_MONOTONIC, &end);
188           timespec_subtract(&d, &end, &start);
189           int fps_now = (1000<<8)/(d.tv_sec*1000+d.tv_nsec/1000000);
190           start = end;
191           fps_avg += (fps_now - fps_avg) >> 3;
192
193           if (opkt->size > max_size)
194                   max_size = opkt->size;
195           if (opkt->size < min_size)
196                   min_size = opkt->size;
197           avg_size = avg_size*frame/(frame+1) + (double)opkt->size/(frame+1);
198           printf("%5d: %2d fps  opkt size: %5d b  max=%5u b min=%5u b avg=%5.0f\n",
199                  frame,
200                  fps_avg>>8,
201                  opkt->size, max_size, min_size, avg_size);
202           if (frame % 100 == 0) max_size=0;
203           frame++;// = (frame + 1) % fps;
204         }
205       }
206       //rt_job_end();
207       av_free_packet(pkt);
208     }
209   }
210
211   return NULL;
212 }
213
214 void wait_for_ending_command(void) {
215   sigset_t sigset;
216   sigemptyset(&sigset);
217   sigaddset(&sigset, SIGINT);
218   sigaddset(&sigset, SIGTERM);
219   sigwaitinfo(&sigset, NULL);
220 }
221 static void block_signals(void) {
222   sigset_t sigset;
223   sigemptyset(&sigset);
224   sigaddset(&sigset, SIGINT);
225   sigaddset(&sigset, SIGTERM);
226   sigprocmask(SIG_BLOCK,&sigset,NULL);
227   pthread_sigmask(SIG_BLOCK,&sigset,NULL);
228 }
229
230
231 int main(int argc, char *argv[])
232 {
233
234   //long int cpu_budget, cpu_period;
235   int ret;
236
237   block_signals();
238
239 #ifdef CONFIG_FFMPEG_WITH_FRSH
240   ret = frsh_init();
241   if (ret) PERROR_AND_EXIT(ret, "frsh_init1");
242
243   /* fill default network contract params */
244   avformat_frsh_budget = 50000; 
245   avformat_frsh_period = 500;
246 #endif /*CONFIG_FFMPEG_WITH_FRSH*/
247
248   avcodec_register_all();
249   av_register_all();
250   avdevice_register_all();
251
252   args_parse(argc, argv);
253
254   s = open_input_stream(vdev, width, height, fps, impform);
255   if (s == NULL) {
256     fprintf(stderr, "Cannot open input file %s\n", vdev);
257
258     return -1;
259   }
260   codec_open(s);
261   os = open_output_stream(dst, dport, CODEC_TYPE_VIDEO);
262   if (os == NULL) {
263     fprintf(stderr, "Cannot open output stream\n");
264
265     return -1;
266   }
267   os->streams[0]->codec->width = s->streams[0]->codec->width;
268   os->streams[0]->codec->height = s->streams[0]->codec->height;
269   os->streams[0]->codec->time_base = s->streams[0]->codec->time_base;
270   os->streams[0]->codec->bit_rate = 1000000;
271   codec_connect(s->streams[0]->codec, os->streams[0]->codec);
272   out_codec_open(os);
273   dump_format(os, 0, os->filename, 1);
274   sdp_print(os, sdp_file);
275
276 #if CONFIG_STREAMER_WITH_FRSH && CONFIG_AQUOSA 
277   frsh_thread_attr_t frsh_attr;
278   frsh_thread_id_t thread;
279   frsh_vres_id_t cpu_vres;
280   frsh_contract_t cpu_contract;
281   frsh_rel_time_t cpu_budget, cpu_period;
282  
283   cpu_budget = fosa_msec_to_rel_time(50);
284   cpu_period = fosa_msec_to_rel_time(100);
285   /* Contract negotiation for CPU */
286   ret = frsh_contract_init(&cpu_contract);
287   if (ret) PERROR_AND_EXIT(ret, "CPU:frsh_contract_init");
288  
289   ret = frsh_contract_set_basic_params(&cpu_contract,
290                                              &cpu_budget,
291                                              &cpu_period,
292                                              FRSH_WT_BOUNDED,
293                                              FRSH_CT_REGULAR);
294         if (ret) PERROR_AND_EXIT(ret, "frsh_contract_set_basic_params");
295         ret = frsh_contract_set_resource_and_label(&cpu_contract, 
296                         FRSH_RT_PROCESSOR, FRSH_CPU_ID_DEFAULT, "aqcpu_cont");
297         if (ret) PERROR_AND_EXIT(ret, "frsh_contract_set_resource_and_label");
298
299         ret = frsh_contract_negotiate(&cpu_contract, &cpu_vres);
300         if (ret) PERROR_AND_EXIT(ret, "frsh_contract_negotiate");
301         printf("Aqcpu vres negotiated\n");
302
303         pthread_attr_init(&frsh_attr);
304         ret = frsh_thread_create_and_bind(cpu_vres, &thread, &frsh_attr, 
305                                 streamer_run, (void*) NULL);
306         if (ret) PERROR_AND_EXIT(ret, "frsh_thread_create_and_bind");
307
308         wait_for_ending_command();
309
310         streamer_run_done_rq = 1;
311         
312         pthread_join(thread.pthread_id, (void**) NULL); 
313
314         printf("Ending contracts\n");
315
316         ret = frsh_contract_cancel(cpu_vres);
317         if (ret) PERROR_AND_EXIT(ret, "frsh_contract_cancel");
318
319         printf("Finishing\n");
320
321         close_output_stream(os);
322 #else
323         pthread_attr_t attr;
324         pthread_t streamer_th;
325
326         pthread_attr_init(&attr);
327
328         ret = pthread_create(&streamer_th, &attr, streamer_run, (void*) NULL);
329         if (ret) 
330                         printf("Failed to create streamer thread\n.");
331
332         wait_for_ending_command();
333
334         streamer_run_done_rq = 1;
335
336         pthread_join(streamer_th, (void**) NULL);
337
338         printf("Finishing\n");
339
340         close_output_stream(os);
341 #endif
342
343   return 0;
344 }
345