Line data Source code
1 : /*
2 : * GPAC - Multimedia Framework C SDK
3 : *
4 : * Authors: Jean Le Feuvre
5 : * Copyright (c) Telecom ParisTech 2018-2021
6 : * All rights reserved
7 : *
8 : * This file is part of GPAC / MPEG-4 part2 video rewrite filter
9 : *
10 : * GPAC is free software; you can redistribute it and/or modify
11 : * it under the terms of the GNU Lesser General Public License as published by
12 : * the Free Software Foundation; either version 2, or (at your option)
13 : * any later version.
14 : *
15 : * GPAC is distributed in the hope that it will be useful,
16 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 : * GNU Lesser General Public License for more details.
19 : *
20 : * You should have received a copy of the GNU Lesser General Public
21 : * License along with this library; see the file COPYING. If not, write to
22 : * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
23 : *
24 : */
25 :
26 : #include <gpac/filters.h>
27 : #include <gpac/constants.h>
28 : #include <gpac/bitstream.h>
29 : #include <gpac/internal/media_dev.h>
30 :
31 : typedef struct
32 : {
33 : //opts
34 : Bool rcfg;
35 :
36 : //only one input pid declared
37 : GF_FilterPid *ipid;
38 : //only one output pid declared
39 : GF_FilterPid *opid;
40 :
41 : u32 crc;
42 : char *dsi;
43 : u32 dsi_size;
44 : } GF_M4VMxCtx;
45 :
46 5 : GF_Err m4vmx_configure_pid(GF_Filter *filter, GF_FilterPid *pid, Bool is_remove)
47 : {
48 : u32 crc;
49 : const GF_PropertyValue *dcd;
50 5 : GF_M4VMxCtx *ctx = gf_filter_get_udta(filter);
51 :
52 5 : if (is_remove) {
53 0 : ctx->ipid = NULL;
54 0 : if (ctx->opid) {
55 0 : gf_filter_pid_remove(ctx->opid);
56 0 : ctx->opid = NULL;
57 : }
58 : return GF_OK;
59 : }
60 5 : if (! gf_filter_pid_check_caps(pid))
61 : return GF_NOT_SUPPORTED;
62 :
63 5 : dcd = gf_filter_pid_get_property(pid, GF_PROP_PID_DECODER_CONFIG);
64 5 : if (!dcd) return GF_NON_COMPLIANT_BITSTREAM;
65 :
66 5 : crc = gf_crc_32(dcd->value.data.ptr, dcd->value.data.size);
67 5 : if (ctx->crc == crc) return GF_OK;
68 5 : ctx->crc = crc;
69 :
70 5 : if (!ctx->opid) {
71 5 : ctx->opid = gf_filter_pid_new(filter);
72 : }
73 : //copy properties at init or reconfig
74 5 : gf_filter_pid_copy_properties(ctx->opid, pid);
75 5 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_UNFRAMED, &PROP_BOOL(GF_TRUE) );
76 :
77 5 : ctx->ipid = pid;
78 :
79 5 : ctx->dsi = dcd->value.data.ptr;
80 5 : ctx->dsi_size = dcd->value.data.size;
81 :
82 5 : gf_filter_pid_set_property(ctx->opid, GF_PROP_PID_DECODER_CONFIG, NULL);
83 5 : gf_filter_pid_set_framing_mode(ctx->ipid, GF_TRUE);
84 5 : return GF_OK;
85 : }
86 :
87 :
88 703 : GF_Err m4vmx_process(GF_Filter *filter)
89 : {
90 703 : GF_M4VMxCtx *ctx = gf_filter_get_udta(filter);
91 : GF_FilterPacket *pck;
92 : u8 *data, *output;
93 : u32 pck_size, size, sap_type;
94 703 : pck = gf_filter_pid_get_packet(ctx->ipid);
95 703 : if (!pck) {
96 21 : if (gf_filter_pid_is_eos(ctx->ipid)) {
97 9 : gf_filter_pid_set_eos(ctx->opid);
98 9 : return GF_EOS;
99 : }
100 : return GF_OK;
101 : }
102 :
103 682 : data = (char *) gf_filter_pck_get_data(pck, &pck_size);
104 :
105 682 : sap_type = gf_filter_pck_get_sap(pck);
106 682 : if (!sap_type) {
107 652 : u8 flags = gf_filter_pck_get_dependency_flags(pck);
108 : //get dependsOn
109 652 : if (flags) {
110 0 : flags>>=4;
111 0 : flags &= 0x3;
112 0 : if (flags==2) sap_type = 3; //could be 1, 2 or 3
113 : }
114 : }
115 :
116 682 : if (sap_type && ctx->dsi) {
117 : GF_FilterPacket *dst_pck;
118 30 : size = pck_size + ctx->dsi_size;
119 :
120 30 : dst_pck = gf_filter_pck_new_alloc(ctx->opid, size, &output);
121 30 : if (!dst_pck) return GF_OUT_OF_MEM;
122 30 : memcpy(output, ctx->dsi, ctx->dsi_size);
123 30 : memcpy(output+ctx->dsi_size, data, pck_size);
124 30 : gf_filter_pck_merge_properties(pck, dst_pck);
125 30 : gf_filter_pck_set_byte_offset(dst_pck, GF_FILTER_NO_BO);
126 30 : gf_filter_pck_send(dst_pck);
127 :
128 30 : if (!ctx->rcfg) {
129 0 : ctx->dsi = NULL;
130 0 : ctx->dsi_size = 0;
131 : }
132 :
133 : } else {
134 652 : gf_filter_pck_forward(pck, ctx->opid);
135 : }
136 682 : gf_filter_pid_drop_packet(ctx->ipid);
137 682 : return GF_OK;
138 : }
139 :
140 : static const GF_FilterCapability M4VMxCaps[] =
141 : {
142 : CAP_UINT(GF_CAPS_INPUT_OUTPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_VISUAL),
143 : CAP_UINT(GF_CAPS_INPUT_OUTPUT,GF_PROP_PID_CODECID, GF_CODECID_MPEG4_PART2),
144 : CAP_BOOL(GF_CAPS_INPUT_EXCLUDED, GF_PROP_PID_UNFRAMED, GF_TRUE),
145 : CAP_BOOL(GF_CAPS_OUTPUT, GF_PROP_PID_UNFRAMED, GF_TRUE),
146 : };
147 :
148 :
149 :
150 : #define OFFS(_n) #_n, offsetof(GF_M4VMxCtx, _n)
151 : static const GF_FilterArgs M4VMxArgs[] =
152 : {
153 : { OFFS(rcfg), "force repeating decoder config at each I-frame", GF_PROP_BOOL, "true", NULL, 0},
154 : {0}
155 : };
156 :
157 :
158 : GF_FilterRegister M4VMxRegister = {
159 : .name = "ufm4v",
160 : GF_FS_SET_DESCRIPTION("M4V writer")
161 : GF_FS_SET_HELP("This filter converts MPEG-4 part 2 visual streams into dumpable format (reinsert decoder config).")
162 : .private_size = sizeof(GF_M4VMxCtx),
163 : .args = M4VMxArgs,
164 : SETCAPS(M4VMxCaps),
165 : .configure_pid = m4vmx_configure_pid,
166 : .process = m4vmx_process
167 : };
168 :
169 :
170 2877 : const GF_FilterRegister *m4vmx_register(GF_FilterSession *session)
171 : {
172 2877 : return &M4VMxRegister;
173 : }
|