1 #include <libavutil/frame.h>
2 
3 #include "audio/aframe.h"
4 #include "common/av_common.h"
5 #include "demux/packet.h"
6 #include "video/mp_image.h"
7 
8 #include "frame.h"
9 
10 struct frame_handler {
11     const char *name;
12     bool is_data;
13     bool is_signaling;
14     void *(*new_ref)(void *data);
15     double (*get_pts)(void *data);
16     void (*set_pts)(void *data, double pts);
17     int (*approx_size)(void *data);
18     AVFrame *(*new_av_ref)(void *data);
19     void *(*from_av_ref)(AVFrame *data);
20     void (*free)(void *data);
21 };
22 
video_ref(void * data)23 static void *video_ref(void *data)
24 {
25     return mp_image_new_ref(data);
26 }
27 
video_get_pts(void * data)28 static double video_get_pts(void *data)
29 {
30     return ((struct mp_image *)data)->pts;
31 }
32 
video_set_pts(void * data,double pts)33 static void video_set_pts(void *data, double pts)
34 {
35     ((struct mp_image *)data)->pts = pts;
36 }
37 
video_approx_size(void * data)38 static int video_approx_size(void *data)
39 {
40     return mp_image_approx_byte_size(data);
41 }
42 
video_new_av_ref(void * data)43 static AVFrame *video_new_av_ref(void *data)
44 {
45     return mp_image_to_av_frame(data);
46 }
47 
video_from_av_ref(AVFrame * data)48 static void *video_from_av_ref(AVFrame *data)
49 {
50     return mp_image_from_av_frame(data);
51 }
52 
audio_ref(void * data)53 static void *audio_ref(void *data)
54 {
55     return mp_aframe_new_ref(data);
56 }
57 
audio_get_pts(void * data)58 static double audio_get_pts(void *data)
59 {
60     return mp_aframe_get_pts(data);
61 }
62 
audio_set_pts(void * data,double pts)63 static void audio_set_pts(void *data, double pts)
64 {
65     mp_aframe_set_pts(data, pts);
66 }
67 
audio_approx_size(void * data)68 static int audio_approx_size(void *data)
69 {
70     return mp_aframe_approx_byte_size(data);
71 }
72 
audio_new_av_ref(void * data)73 static AVFrame *audio_new_av_ref(void *data)
74 {
75     return mp_aframe_to_avframe(data);
76 }
77 
audio_from_av_ref(AVFrame * data)78 static void *audio_from_av_ref(AVFrame *data)
79 {
80     return mp_aframe_from_avframe(data);
81 }
82 
packet_ref(void * data)83 static void *packet_ref(void *data)
84 {
85     return demux_copy_packet(data);
86 }
87 
88 static const struct frame_handler frame_handlers[] = {
89     [MP_FRAME_NONE] = {
90         .name = "none",
91     },
92     [MP_FRAME_EOF] = {
93         .name = "eof",
94         .is_signaling = true,
95     },
96     [MP_FRAME_VIDEO] = {
97         .name = "video",
98         .is_data = true,
99         .new_ref = video_ref,
100         .get_pts = video_get_pts,
101         .set_pts = video_set_pts,
102         .approx_size = video_approx_size,
103         .new_av_ref = video_new_av_ref,
104         .from_av_ref = video_from_av_ref,
105         .free = talloc_free,
106     },
107     [MP_FRAME_AUDIO] = {
108         .name = "audio",
109         .is_data = true,
110         .new_ref = audio_ref,
111         .get_pts = audio_get_pts,
112         .set_pts = audio_set_pts,
113         .approx_size = audio_approx_size,
114         .new_av_ref = audio_new_av_ref,
115         .from_av_ref = audio_from_av_ref,
116         .free = talloc_free,
117     },
118     [MP_FRAME_PACKET] = {
119         .name = "packet",
120         .is_data = true,
121         .new_ref = packet_ref,
122         .free = talloc_free,
123     },
124 };
125 
mp_frame_type_str(enum mp_frame_type t)126 const char *mp_frame_type_str(enum mp_frame_type t)
127 {
128     return frame_handlers[t].name;
129 }
130 
mp_frame_is_data(struct mp_frame frame)131 bool mp_frame_is_data(struct mp_frame frame)
132 {
133     return frame_handlers[frame.type].is_data;
134 }
135 
mp_frame_is_signaling(struct mp_frame frame)136 bool mp_frame_is_signaling(struct mp_frame frame)
137 {
138     return frame_handlers[frame.type].is_signaling;
139 }
140 
mp_frame_unref(struct mp_frame * frame)141 void mp_frame_unref(struct mp_frame *frame)
142 {
143     if (!frame)
144         return;
145 
146     if (frame_handlers[frame->type].free)
147         frame_handlers[frame->type].free(frame->data);
148 
149     *frame = (struct mp_frame){0};
150 }
151 
mp_frame_ref(struct mp_frame frame)152 struct mp_frame mp_frame_ref(struct mp_frame frame)
153 {
154     if (frame_handlers[frame.type].new_ref) {
155         assert(frame.data);
156         frame.data = frame_handlers[frame.type].new_ref(frame.data);
157         if (!frame.data)
158             frame.type = MP_FRAME_NONE;
159     }
160     return frame;
161 }
162 
mp_frame_get_pts(struct mp_frame frame)163 double mp_frame_get_pts(struct mp_frame frame)
164 {
165     if (frame_handlers[frame.type].get_pts)
166         return frame_handlers[frame.type].get_pts(frame.data);
167     return MP_NOPTS_VALUE;
168 }
169 
mp_frame_set_pts(struct mp_frame frame,double pts)170 void mp_frame_set_pts(struct mp_frame frame, double pts)
171 {
172     if (frame_handlers[frame.type].get_pts)
173         frame_handlers[frame.type].set_pts(frame.data, pts);
174 }
175 
mp_frame_approx_size(struct mp_frame frame)176 int mp_frame_approx_size(struct mp_frame frame)
177 {
178     if (frame_handlers[frame.type].approx_size)
179         return frame_handlers[frame.type].approx_size(frame.data);
180     return 0;
181 }
182 
mp_frame_to_av(struct mp_frame frame,struct AVRational * tb)183 AVFrame *mp_frame_to_av(struct mp_frame frame, struct AVRational *tb)
184 {
185     if (!frame_handlers[frame.type].new_av_ref)
186         return NULL;
187 
188     AVFrame *res = frame_handlers[frame.type].new_av_ref(frame.data);
189     if (!res)
190         return NULL;
191 
192     res->pts = mp_pts_to_av(mp_frame_get_pts(frame), tb);
193     return res;
194 }
195 
mp_frame_from_av(enum mp_frame_type type,struct AVFrame * frame,struct AVRational * tb)196 struct mp_frame mp_frame_from_av(enum mp_frame_type type, struct AVFrame *frame,
197                                  struct AVRational *tb)
198 {
199     struct mp_frame res = {type};
200 
201     if (!frame_handlers[res.type].from_av_ref)
202         return MP_NO_FRAME;
203 
204     res.data = frame_handlers[res.type].from_av_ref(frame);
205     if (!res.data)
206         return MP_NO_FRAME;
207 
208     mp_frame_set_pts(res, mp_pts_from_av(frame->pts, tb));
209     return res;
210 }
211