]> git.sesse.net Git - vlc/blob - modules/access/timecode.c
mux: avi: fix leak on format failure
[vlc] / modules / access / timecode.c
1 /**
2  * @file timecode.c
3  * @brief Time code sub-picture generator for VLC media player
4  */
5 /*****************************************************************************
6  * Copyright © 2013 Rémi Denis-Courmont
7  *
8  * This program is free software; you can redistribute it and/or modify it
9  * under the terms of the GNU Lesser General Public License as published by
10  * the Free Software Foundation; either version 2.1 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public License
19  * along with this program; if not, write to the Free Software Foundation,
20  * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21  *****************************************************************************/
22
23 #ifdef HAVE_CONFIG_H
24 # include <config.h>
25 #endif
26
27 #include <stdlib.h>
28 #include <assert.h>
29
30 #include <vlc_common.h>
31 #include <vlc_demux.h>
32 #include <vlc_plugin.h>
33
34 #define FPS_TEXT N_("Frame rate")
35
36 static int  Open (vlc_object_t *);
37 static void Close (vlc_object_t *);
38
39 static const char *const fps_values[] = { "24/1", "25/1", "30000/1001", "30/1" };
40 static const char *const fps_texts[] = { "24", "25", "29.97", "30" };
41
42 vlc_module_begin ()
43     set_shortname (N_("Time code"))
44     set_description (N_("Time code subpicture elementary stream generator"))
45     set_category (CAT_INPUT)
46     set_subcategory (SUBCAT_INPUT_ACCESS)
47     set_capability ("access_demux", 0)
48     set_callbacks (Open, Close)
49
50     add_string ("timecode-fps", "25/1", FPS_TEXT, FPS_TEXT, false)
51         change_string_list (fps_values, fps_texts)
52         change_safe ()
53 vlc_module_end ()
54
55 struct demux_sys_t
56 {
57     es_out_id_t *es;
58     date_t date;
59     mtime_t next_time;
60 };
61
62 static int DemuxOnce (demux_t *demux, bool master)
63 {
64     demux_sys_t *sys = demux->p_sys;
65     mtime_t pts = date_Get (&sys->date);
66     lldiv_t d;
67     unsigned h, m, s, f;
68
69     d = lldiv (pts, CLOCK_FREQ);
70     f = d.rem * sys->date.i_divider_num / sys->date.i_divider_den / CLOCK_FREQ;
71     d = lldiv (d.quot, 60);
72     s = d.rem;
73     d = lldiv (d.quot, 60);
74     m = d.rem;
75     h = d.quot;
76
77     char *str;
78     int len = asprintf (&str, "%02u:%02u:%02u:%02u", h, m, s, f);
79     if (len == -1)
80         return -1;
81
82     block_t *block = block_heap_Alloc (str, len + 1);
83     if (unlikely(block == NULL))
84         return -1;
85
86     block->i_buffer = len;
87     assert(str[len] == '\0');
88
89     block->i_pts = block->i_dts = pts;
90     block->i_length = date_Increment (&sys->date, 1) - pts;
91     es_out_Send (demux->out, sys->es, block);
92     if (master)
93         es_out_Control (demux->out, ES_OUT_SET_PCR, pts);
94     return 1;
95 }
96
97 static int Demux (demux_t *demux)
98 {
99     demux_sys_t *sys = demux->p_sys;
100
101     if (sys->next_time == VLC_TS_INVALID) /* Master mode */
102         return DemuxOnce (demux, true);
103
104     /* Slave mode */
105     while (sys->next_time > date_Get (&sys->date))
106     {
107         int val = DemuxOnce (demux, false);
108         if (val <= 0)
109             return val;
110     }
111     return 1;
112 }
113
114 static int Control (demux_t *demux, int query, va_list args)
115 {
116     demux_sys_t *sys = demux->p_sys;
117
118     switch (query)
119     {
120         case DEMUX_GET_POSITION:
121             *va_arg (args, float *) = 0.f;
122             break;
123
124         case DEMUX_GET_LENGTH:
125             *va_arg (args, int64_t *) = INT64_C(0);
126             break;
127
128         case DEMUX_GET_TIME:
129             *va_arg (args, int64_t *) = date_Get (&sys->date);
130             break;
131
132         case DEMUX_SET_TIME:
133             date_Set (&sys->date, va_arg (args, int64_t));
134             break;
135
136         case DEMUX_SET_NEXT_DEMUX_TIME:
137         {
138             const mtime_t pts = va_arg (args, int64_t );
139
140             if (sys->next_time == VLC_TS_INVALID) /* first invocation? */
141             {
142                 date_Set (&sys->date, pts);
143                 date_Decrement (&sys->date, 1);
144             }
145             sys->next_time = pts;
146             break;
147         }
148
149         case DEMUX_GET_PTS_DELAY:
150         {
151             int64_t *v = va_arg (args, int64_t *);
152             *v = INT64_C(1000) * var_InheritInteger (demux, "live-caching");
153             break;
154         }
155
156         case DEMUX_CAN_PAUSE:
157         case DEMUX_CAN_CONTROL_PACE:
158         case DEMUX_CAN_SEEK:
159             *va_arg (args, bool *) = true;
160             break;
161
162         default:
163             return VLC_EGENERIC;
164     }
165     return VLC_SUCCESS;
166 }
167
168 static int Open (vlc_object_t *obj)
169 {
170     demux_t *demux = (demux_t *)obj;
171     demux_sys_t *sys = malloc (sizeof (*sys));
172
173     if (unlikely(sys == NULL))
174         return VLC_ENOMEM;
175
176     es_format_t fmt;
177     es_format_Init (&fmt, SPU_ES, VLC_CODEC_ITU_T140);
178     sys->es = es_out_Add (demux->out, &fmt);
179
180     unsigned num, den;
181     if (var_InheritURational (demux, &num, &den, "timecode-fps")
182      || !num || !den)
183     {
184         msg_Err (demux, "invalid frame rate");
185         free (sys);
186         return VLC_EGENERIC;
187     }
188
189     date_Init (&sys->date, num, den);
190     date_Set (&sys->date, VLC_TS_0);
191     sys->next_time = VLC_TS_INVALID;
192
193     demux->p_sys = sys;
194     demux->pf_demux   = Demux;
195     demux->pf_control = Control;
196     return VLC_SUCCESS;
197 }
198
199 static void Close (vlc_object_t *obj)
200 {
201     demux_t *demux = (demux_t *)obj;
202     demux_sys_t *sys = demux->p_sys;
203
204     free (sys);
205 }