Skip to content

Commit 6737134

Browse files
authored
Add AVI writer (#4385)
1 parent 43a652a commit 6737134

File tree

12 files changed

+788
-57
lines changed

12 files changed

+788
-57
lines changed

pjmedia/build/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ export _LDFLAGS := $(APP_THIRD_PARTY_LIBS) \
5858
#
5959
export PJMEDIA_SRCDIR = ../src/pjmedia
6060
export PJMEDIA_OBJS += $(OS_OBJS) $(M_OBJS) $(CC_OBJS) $(HOST_OBJS) \
61-
alaw_ulaw.o alaw_ulaw_table.o avi_player.o av_sync.o \
61+
alaw_ulaw.o alaw_ulaw_table.o avi_player.o avi_writer.o av_sync.o \
6262
bidirectional.o clock_thread.o codec.o conference.o \
6363
conf_switch.o converter.o converter_libswscale.o converter_libyuv.o \
6464
delaybuf.o echo_common.o \

pjmedia/build/pjmedia.vcproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3350,6 +3350,10 @@
33503350
RelativePath="..\src\pjmedia\avi_player.c"
33513351
>
33523352
</File>
3353+
<File
3354+
RelativePath="..\src\pjmedia\avi_writer.c"
3355+
>
3356+
</File>
33533357
<File
33543358
RelativePath="..\src\pjmedia\bidirectional.c"
33553359
>

pjmedia/build/pjmedia.vcxproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -610,6 +610,7 @@
610610
<ClCompile Include="..\src\pjmedia\alaw_ulaw_table.c" />
611611
<ClCompile Include="..\src\pjmedia\audiodev.c" />
612612
<ClCompile Include="..\src\pjmedia\avi_player.c" />
613+
<ClCompile Include="..\src\pjmedia\avi_writer.c" />
613614
<ClCompile Include="..\src\pjmedia\av_sync.c" />
614615
<ClCompile Include="..\src\pjmedia\bidirectional.c" />
615616
<ClCompile Include="..\src\pjmedia\clock_thread.c" />

pjmedia/build/pjmedia.vcxproj.filters

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@
2020
<ClCompile Include="..\src\pjmedia\avi_player.c">
2121
<Filter>Source Files</Filter>
2222
</ClCompile>
23+
<ClCompile Include="..\src\pjmedia\avi_writer.c">
24+
<Filter>Source Files</Filter>
25+
</ClCompile>
2326
<ClCompile Include="..\src\pjmedia\bidirectional.c">
2427
<Filter>Source Files</Filter>
2528
</ClCompile>

pjmedia/include/pjmedia/avi.h

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,48 @@ typedef struct pjmedia_avi_subchunk
191191
} pjmedia_avi_subchunk;
192192

193193

194+
/**
195+
* Internal function to normalize data from AVI's little endian to host
196+
* byte order and vice versa.
197+
*/
198+
#if defined(PJ_IS_BIG_ENDIAN) && PJ_IS_BIG_ENDIAN!=0
199+
static void pjmedia_avi_swap_data(void *data, pj_uint8_t bits,
200+
unsigned count)
201+
{
202+
unsigned i;
203+
204+
count /= (bits == 32? 4 : 2);
205+
206+
if (bits == 32) {
207+
pj_int32_t *data32 = (pj_int32_t *)data;
208+
for (i = 0; i < count; ++i)
209+
data32[i] = pj_swap32(data32[i]);
210+
} else if (bits == 16) {
211+
pj_int16_t *data16 = (pj_int16_t *)data;
212+
for (i = 0; i < count; ++i)
213+
data16[i] = pj_swap16(data16[i]);
214+
}
215+
216+
}
217+
static void pjmedia_avi_swap_data2(void *data, pj_uint8_t nsizes,
218+
pj_uint8_t *sizes)
219+
{
220+
unsigned i;
221+
pj_int8_t *datap = (pj_int8_t *)data;
222+
for (i = 0; i < nsizes; i++) {
223+
pjmedia_avi_swap_data(datap, 32, sizes[i]);
224+
datap += sizes[i++];
225+
if (i >= nsizes)
226+
break;
227+
pjmedia_avi_swap_data(datap, 16, sizes[i]);
228+
datap += sizes[i];
229+
}
230+
}
231+
#else
232+
# define pjmedia_avi_swap_data(data, bits, count)
233+
# define pjmedia_avi_swap_data2(data, nsizes, sizes)
234+
#endif
235+
194236
PJ_END_DECL
195237

196238
/**

pjmedia/include/pjmedia/avi_stream.h

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525
#include <pjmedia/port.h>
2626

2727

28-
2928
PJ_BEGIN_DECL
3029

3130

@@ -65,6 +64,13 @@ typedef pjmedia_port pjmedia_avi_stream;
6564
*/
6665
typedef struct pjmedia_avi_streams pjmedia_avi_streams;
6766

67+
struct pjmedia_avi_streams
68+
{
69+
pj_pool_t *pool;
70+
unsigned num_streams;
71+
pjmedia_port **streams;
72+
};
73+
6874
/**
6975
* Create avi streams to play an AVI file. AVI player supports
7076
* reading AVI file with uncompressed video format and
@@ -201,6 +207,60 @@ pjmedia_avi_stream_set_eof_cb2(pjmedia_avi_stream *stream,
201207
* @}
202208
*/
203209

210+
/**
211+
* @defgroup PJMEDIA_AVI_FILE_WRITE AVI File Writer
212+
* @ingroup PJMEDIA_PORT
213+
* @brief Video and audio recording to AVI file
214+
* @{
215+
*/
216+
217+
/**
218+
* Create avi streams to write to an AVI file. AVI writer supports
219+
* recording AVI file with uncompressed video format and
220+
* 16 bit PCM.
221+
*
222+
* Note that video recording file size can grow very quickly, and
223+
* once it reaches the maximum size specified, the file will be
224+
* automatically closed and the callback (if any) will be called.
225+
*
226+
* @param pool Pool to create the streams.
227+
* @param filename File name to write to.
228+
* @param max_fsize Maximum file size.
229+
* @param num_streams Number of streams to write. Typically this should be
230+
* 2, one for video, and one for audio.
231+
* @param format The format of the streams.
232+
* @param flags Avi streams creation flags. Currently must be zero.
233+
* @param p_streams Pointer to receive the avi streams instance.
234+
*
235+
* @return PJ_SUCCESS on success.
236+
*/
237+
PJ_DECL(pj_status_t)
238+
pjmedia_avi_writer_create_streams(pj_pool_t *pool,
239+
const char *filename,
240+
pj_uint32_t max_fsize,
241+
unsigned num_streams,
242+
const pjmedia_format format[],
243+
unsigned flags,
244+
pjmedia_avi_streams **p_streams);
245+
246+
247+
/**
248+
* Register the callback to be called when the file writing has reached
249+
* maximum size.
250+
*
251+
* @param streams The AVI writer streams.
252+
* @param user_data User data to be specified in the callback, and will be
253+
* given on the callback.
254+
* @param cb Callback to be called.
255+
*
256+
* @return PJ_SUCCESS on success.
257+
*/
258+
PJ_DECL(pj_status_t)
259+
pjmedia_avi_streams_set_cb(pjmedia_avi_streams *streams,
260+
void *user_data,
261+
void (*cb)(pjmedia_avi_streams *streams,
262+
void *usr_data));
263+
204264

205265
PJ_END_DECL
206266

pjmedia/include/pjmedia/signatures.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,8 +170,9 @@ PJ_INLINE(const char*) pjmedia_sig_name(pjmedia_obj_sig sig, char buf[])
170170
#define PJMEDIA_SIG_CLASS_PORT_VID(c,d) PJMEDIA_SIG_CLASS_PORT('V',c,d)
171171
#define PJMEDIA_SIG_IS_CLASS_PORT_VID(s) ((s)>>24=='P' && (((s)>>16)&0xff)=='V')
172172

173-
/** AVI player signature. */
173+
/** AVI player and writer signature. */
174174
#define PJMEDIA_SIG_PORT_VID_AVI_PLAYER PJMEDIA_SIG_CLASS_PORT_VID('A','V')
175+
#define PJMEDIA_SIG_PORT_VID_AVI_WRITER PJMEDIA_SIG_CLASS_PORT_VID('A','W')
175176
#define PJMEDIA_SIG_PORT_VID_STREAM PJMEDIA_SIG_CLASS_PORT_VID('S','T')
176177
#define PJMEDIA_SIG_PORT_VID_TEE PJMEDIA_SIG_CLASS_PORT_VID('T','E')
177178

pjmedia/src/pjmedia/avi_player.c

Lines changed: 21 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -60,42 +60,8 @@
6060
# define TRACE_(x)
6161
#endif
6262

63-
#if defined(PJ_IS_BIG_ENDIAN) && PJ_IS_BIG_ENDIAN!=0
64-
static void data_to_host(void *data, pj_uint8_t bits, unsigned count)
65-
{
66-
unsigned i;
67-
68-
count /= (bits == 32? 4 : 2);
69-
70-
if (bits == 32) {
71-
pj_int32_t *data32 = (pj_int32_t *)data;
72-
for (i=0; i<count; ++i)
73-
data32[i] = pj_swap32(data32[i]);
74-
} else {
75-
pj_int16_t *data16 = (pj_int16_t *)data;
76-
for (i=0; i<count; ++i)
77-
data16[i] = pj_swap16(data16[i]);
78-
}
79-
80-
}
81-
static void data_to_host2(void *data, pj_uint8_t nsizes,
82-
pj_uint8_t *sizes)
83-
{
84-
unsigned i;
85-
pj_int8_t *datap = (pj_int8_t *)data;
86-
for (i = 0; i < nsizes; i++) {
87-
data_to_host(datap, 32, sizes[i]);
88-
datap += sizes[i++];
89-
if (i >= nsizes)
90-
break;
91-
data_to_host(datap, 16, sizes[i]);
92-
datap += sizes[i];
93-
}
94-
}
95-
#else
96-
# define data_to_host(data, bits, count)
97-
# define data_to_host2(data, nsizes, sizes)
98-
#endif
63+
#define data_to_host pjmedia_avi_swap_data
64+
#define data_to_host2 pjmedia_avi_swap_data2
9965

10066
typedef struct avi_fmt_info
10167
{
@@ -117,16 +83,14 @@ static avi_fmt_info avi_fmts[] =
11783
{PJMEDIA_FORMAT_PACK('D','X','5','0'), PJMEDIA_FORMAT_MPEG4}
11884
};
11985

120-
struct pjmedia_avi_streams
86+
typedef struct avi_reader_streams
12187
{
122-
pj_pool_t *pool;
123-
unsigned num_streams;
124-
pjmedia_port **streams;
88+
pjmedia_avi_streams base;
12589

12690
/* AV synchronization */
12791
pjmedia_av_sync *avsync;
12892
pj_size_t eof_cnt;
129-
};
93+
} avi_reader_streams;
13094

13195
struct avi_reader_port
13296
{
@@ -148,7 +112,7 @@ struct avi_reader_port
148112
/* AV synchronization */
149113
pjmedia_av_sync_media *avsync_media;
150114
pj_size_t slow_down_frm;
151-
pjmedia_avi_streams *avi_streams;
115+
avi_reader_streams *avi_streams;
152116

153117
pj_status_t (*cb)(pjmedia_port*, void*);
154118
pj_bool_t subscribed;
@@ -214,11 +178,11 @@ static pj_status_t file_read3(pj_oshandle_t fd, void *data, pj_ssize_t size,
214178

215179
static void streams_on_destroy(void *arg)
216180
{
217-
pjmedia_avi_streams *streams = (pjmedia_avi_streams*)arg;
181+
avi_reader_streams *streams = (avi_reader_streams *)arg;
218182

219183
if (streams->avsync)
220184
pjmedia_av_sync_destroy(streams->avsync);
221-
pj_pool_safe_release(&streams->pool);
185+
pj_pool_safe_release(&streams->base.pool);
222186
}
223187

224188

@@ -245,6 +209,7 @@ pjmedia_avi_player_create_streams(pj_pool_t *pool_,
245209
unsigned options,
246210
pjmedia_avi_streams **p_streams)
247211
{
212+
avi_reader_streams *streams = NULL;
248213
pjmedia_avi_hdr avi_hdr;
249214
struct avi_reader_port *fport[PJMEDIA_AVI_MAX_NUM_STREAMS];
250215
pj_off_t pos;
@@ -596,7 +561,8 @@ pjmedia_avi_player_create_streams(pj_pool_t *pool_,
596561
}
597562

598563
/* Done. */
599-
*p_streams = pj_pool_calloc(pool, 1, sizeof(pjmedia_avi_streams));
564+
streams = pj_pool_calloc(pool, 1, sizeof(avi_reader_streams));
565+
*p_streams = (pjmedia_avi_streams *)streams;
600566
(*p_streams)->num_streams = nstr;
601567
(*p_streams)->streams = pj_pool_calloc(pool, (*p_streams)->num_streams,
602568
sizeof(pjmedia_port *));
@@ -615,7 +581,7 @@ pjmedia_avi_player_create_streams(pj_pool_t *pool_,
615581
if (status != PJ_SUCCESS)
616582
goto on_error;
617583

618-
(*p_streams)->avsync = avsync;
584+
streams->avsync = avsync;
619585

620586
for (i = 0; i < nstr; i++) {
621587
pjmedia_av_sync_media_setting med_setting;
@@ -640,7 +606,7 @@ pjmedia_avi_player_create_streams(pj_pool_t *pool_,
640606
goto on_error;
641607

642608
/* Set pointer to AVI streams */
643-
fport[i]->avi_streams = *p_streams;
609+
fport[i]->avi_streams = streams;
644610
}
645611
}
646612

@@ -667,12 +633,12 @@ pjmedia_avi_player_create_streams(pj_pool_t *pool_,
667633
pjmedia_port_destroy(&fport[i]->base);
668634
}
669635

670-
if (*p_streams && (*p_streams)->avsync) {
636+
if (streams && streams->avsync) {
671637
for (i = 0; i < nstr; i++) {
672638
if (fport[i]->avsync_media)
673639
pjmedia_av_sync_del_media(NULL, fport[i]->avsync_media);
674640
}
675-
pjmedia_av_sync_destroy((*p_streams)->avsync);
641+
pjmedia_av_sync_destroy(streams->avsync);
676642
}
677643

678644
pj_pool_release(pool);
@@ -1006,9 +972,10 @@ static pj_status_t avi_get_frame(pjmedia_port *this_port,
1006972

1007973
/* If synchronized, wait all streams to EOF before rewinding */
1008974
if (fport->avsync_media) {
1009-
pjmedia_avi_streams *avi_streams = fport->avi_streams;
975+
avi_reader_streams *avi_streams = fport->avi_streams;
1010976

1011-
rewind_now = (avi_streams->eof_cnt % avi_streams->num_streams)==0;
977+
rewind_now = (avi_streams->eof_cnt %
978+
avi_streams->base.num_streams)==0;
1012979
if (rewind_now) {
1013980
pj_timestamp ts_zero = {{0}};
1014981
pjmedia_av_sync_update_ref(fport->avsync_media,
@@ -1222,10 +1189,11 @@ static pj_status_t avi_get_frame(pjmedia_port *this_port,
12221189

12231190
/* Reset AV sync on the last stream encountering EOF */
12241191
if (fport->avsync_media) {
1225-
pjmedia_avi_streams* avi_streams = fport->avi_streams;
1192+
avi_reader_streams *avi_streams = fport->avi_streams;
12261193

12271194
if (avi_streams->avsync &&
1228-
(++avi_streams->eof_cnt % avi_streams->num_streams == 0))
1195+
(++avi_streams->eof_cnt %
1196+
avi_streams->base.num_streams == 0))
12291197
{
12301198
pjmedia_av_sync_reset(avi_streams->avsync);
12311199
}

0 commit comments

Comments
 (0)