Skip to content

Commit 125ee0d

Browse files
authored
Misc updates on AVI writer (#4528)
* Misc updates on avi writer - Apply 'db' prefix (uncompressed) in video data chunk fourcc. - Update AVI headers when port is destroyed, was only when file size limit is reached. - Fix compile warnings. The generated AVI file is now playable in VLC Media Player, but it still doesn't work in Windows Media Player.
1 parent 4de1bb8 commit 125ee0d

File tree

2 files changed

+68
-48
lines changed

2 files changed

+68
-48
lines changed

pjmedia/include/pjmedia/avi.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,8 @@ struct pjmedia_avi_hdr
181181
*/
182182
typedef struct pjmedia_avi_hdr pjmedia_avi_hdr;
183183

184+
#pragma pack(4)
185+
184186
/**
185187
* This structure describes generic RIFF subchunk header.
186188
*/
@@ -190,6 +192,7 @@ typedef struct pjmedia_avi_subchunk
190192
pj_uint32_t len; /**< Length following this field */
191193
} pjmedia_avi_subchunk;
192194

195+
#pragma pack()
193196

194197
/**
195198
* Internal function to normalize data from AVI's little endian to host

pjmedia/src/pjmedia/avi_writer.c

Lines changed: 65 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -67,31 +67,31 @@ struct avi_port
6767
avi_writer_streams *streams;
6868
};
6969

70-
static pj_status_t write_headers(avi_writer_streams *streams)
70+
static pj_status_t write_headers(pj_oshandle_t fd, avi_writer_streams *streams)
7171
{
7272
unsigned i;
7373
pj_ssize_t size;
7474
pj_status_t status;
7575

7676
/* Write AVI header. */
7777
size = sizeof(riff_hdr_t) + sizeof(avih_hdr_t);
78-
status = pj_file_write(streams->fd, &streams->avi_hdr, &size);
78+
status = pj_file_write(fd, &streams->avi_hdr, &size);
7979
if (status != PJ_SUCCESS)
8080
return status;
8181
streams->total += size;
8282

8383
/* Write stream headers. */
8484
for (i = 0; i < streams->base.num_streams; i++) {
8585
size = sizeof(strl_hdr_t);
86-
status = pj_file_write(streams->fd, &streams->avi_hdr.strl_hdr[i],
86+
status = pj_file_write(fd, &streams->avi_hdr.strl_hdr[i],
8787
&size);
8888
if (status != PJ_SUCCESS)
8989
return status;
9090
streams->total += size;
9191

9292
size = streams->base.streams[i]->info.fmt.type == PJMEDIA_TYPE_AUDIO?
9393
sizeof(strf_audio_hdr_t): sizeof(strf_video_hdr_t);
94-
status = pj_file_write(streams->fd, &streams->avi_hdr.strf_hdr[i],
94+
status = pj_file_write(fd, &streams->avi_hdr.strf_hdr[i],
9595
&size);
9696
if (status != PJ_SUCCESS)
9797
return status;
@@ -101,6 +101,55 @@ static pj_status_t write_headers(avi_writer_streams *streams)
101101
return PJ_SUCCESS;
102102
}
103103

104+
static void close_avi_file(avi_writer_streams *streams)
105+
{
106+
pj_off_t file_size;
107+
unsigned i;
108+
pj_status_t status;
109+
pj_oshandle_t fd;
110+
111+
/* First, reset file handle, best effort in handling race conditions */
112+
fd = streams->fd;
113+
streams->fd = (pj_oshandle_t)(pj_ssize_t)-1;
114+
115+
/* Already closed. */
116+
if (fd == (pj_oshandle_t)(pj_ssize_t)-1)
117+
return;
118+
119+
/* Set AVI header's file length and total frames. */
120+
status = pj_file_getpos(fd, &file_size);
121+
if (status != PJ_SUCCESS)
122+
goto on_return;
123+
124+
streams->avi_hdr.riff_hdr.file_len = (pj_uint32_t)
125+
(file_size - 8);
126+
pjmedia_avi_swap_data(&streams->avi_hdr.riff_hdr.file_len,
127+
sizeof(pj_uint32_t), 32);
128+
streams->avi_hdr.avih_hdr.tot_frames = (pj_uint32_t)streams->frame_cnt;
129+
pjmedia_avi_swap_data(&streams->avi_hdr.avih_hdr.tot_frames,
130+
sizeof(pj_uint32_t), 32);
131+
132+
for (i = 0; i < streams->base.num_streams; i++) {
133+
pjmedia_avi_swap_data(&streams->avi_hdr.strl_hdr[i].length,
134+
sizeof(pj_uint32_t), 32);
135+
}
136+
137+
/* Rewrite headers. */
138+
status = pj_file_setpos(fd, 0, PJ_SEEK_SET);
139+
if (status != PJ_SUCCESS)
140+
goto on_return;
141+
status = write_headers(fd, streams);
142+
if (status != PJ_SUCCESS)
143+
goto on_return;
144+
145+
on_return:
146+
pj_file_close(fd);
147+
if (status != PJ_SUCCESS) {
148+
pj_perror(2, THIS_FILE, status,
149+
"Error updating length & frame count in AVI header");
150+
}
151+
}
152+
104153
static pj_status_t file_on_event(pjmedia_event *event,
105154
void *user_data)
106155
{
@@ -140,41 +189,10 @@ static pj_status_t avi_put_frame(pjmedia_port *this_port,
140189
if (fport->streams->total + frame->size + sizeof(pjmedia_avi_subchunk) >
141190
fport->streams->max_size)
142191
{
143-
pj_off_t file_size;
144-
unsigned i;
145-
146192
PJ_LOG(4, (THIS_FILE, "AVI writer max size %zu reached",
147193
fport->streams->max_size));
148194

149-
/* Set AVI header's file length and total frames. */
150-
status = pj_file_getpos(fport->streams->fd, &file_size);
151-
if (status != PJ_SUCCESS)
152-
goto on_return;
153-
154-
fport->streams->avi_hdr.riff_hdr.file_len = (pj_uint32_t)
155-
(file_size - 8);
156-
pjmedia_avi_swap_data(&fport->streams->avi_hdr.riff_hdr.file_len,
157-
sizeof(pj_uint32_t), 32);
158-
fport->streams->avi_hdr.avih_hdr.tot_frames =fport->streams->frame_cnt;
159-
pjmedia_avi_swap_data(&fport->streams->avi_hdr.avih_hdr.tot_frames,
160-
sizeof(pj_uint32_t), 32);
161-
162-
for (i = 0; i < fport->streams->base.num_streams; i++) {
163-
pjmedia_avi_swap_data(&fport->streams->avi_hdr.strl_hdr[i].length,
164-
sizeof(pj_uint32_t), 32);
165-
}
166-
167-
/* Rewrite headers. */
168-
status = pj_file_setpos(fport->streams->fd, 0, PJ_SEEK_SET);
169-
if (status != PJ_SUCCESS)
170-
goto on_return;
171-
status = write_headers(fport->streams);
172-
if (status != PJ_SUCCESS)
173-
goto on_return;
174-
175-
/* Close file. */
176-
pj_file_close(fport->streams->fd);
177-
fport->streams->fd = (pj_oshandle_t)(pj_ssize_t)-1;
195+
close_avi_file(fport->streams);
178196

179197
/* Call callback. */
180198
if (fport->streams->cb2) {
@@ -202,8 +220,10 @@ static pj_status_t avi_put_frame(pjmedia_port *this_port,
202220
/* Write subchunk header. */
203221
ch.id = 0;
204222
((char *)&ch.id)[0] = '0';
205-
((char *)&ch.id)[1] = '0' + fport->stream_id;
206-
ch.len = frame->size;
223+
((char *)&ch.id)[1] = '0' + (char)fport->stream_id;
224+
((char *)&ch.id)[2] = 'd';
225+
((char *)&ch.id)[3] = 'b';
226+
ch.len = (pj_uint32_t)frame->size;
207227
size = sizeof(ch);
208228
pjmedia_avi_swap_data(&ch, sizeof(ch), 32);
209229

@@ -246,11 +266,7 @@ static void streams_on_destroy(void *arg)
246266
streams->subscribed = PJ_FALSE;
247267
}
248268

249-
if (streams->fd != (pj_oshandle_t) (pj_ssize_t)-1) {
250-
pj_file_close(streams->fd);
251-
streams->fd = (pj_oshandle_t)(pj_ssize_t)-1;
252-
}
253-
269+
close_avi_file(streams);
254270
pj_pool_safe_release(&streams->base.pool);
255271
}
256272

@@ -401,7 +417,7 @@ pjmedia_avi_writer_create_streams(pj_pool_t *pool_,
401417
avi_hdr.strl_hdr[i].codec = format[i].id;
402418
avi_hdr.strl_hdr[i].rate = afd->clock_rate;
403419
avi_hdr.strl_hdr[i].scale = 1;
404-
avi_hdr.strl_hdr[i].quality = -1;
420+
avi_hdr.strl_hdr[i].quality = (pj_uint32_t)-1;
405421
avi_hdr.strl_hdr[i].buf_size = 0;
406422
avi_hdr.strl_hdr[i].sample_size = afd->bits_per_sample / 8;
407423
avi_hdr.strl_hdr[i].length = 0; /* will be filled later */
@@ -410,11 +426,12 @@ pjmedia_avi_writer_create_streams(pj_pool_t *pool_,
410426
strf_hdr->strf = SET_TAG(PJMEDIA_AVI_STRF_TAG);
411427
strf_hdr->strf_size = sizeof(strf_audio_hdr_t) - 8;
412428
strf_hdr->fmt_tag = 1; /* 1 for PCM */
413-
strf_hdr->nchannels = afd->channel_count;
429+
strf_hdr->nchannels = (pj_uint16_t)afd->channel_count;
414430
strf_hdr->sample_rate = afd->clock_rate;
415-
strf_hdr->block_align = afd->channel_count * afd->bits_per_sample / 8;
431+
strf_hdr->block_align = (pj_uint16_t)(afd->channel_count *
432+
afd->bits_per_sample / 8);
416433
strf_hdr->bytes_per_sec = strf_hdr->sample_rate * strf_hdr->block_align;
417-
strf_hdr->bits_per_sample = afd->bits_per_sample;
434+
strf_hdr->bits_per_sample = (pj_uint16_t)afd->bits_per_sample;
418435

419436
/* Normalize header to AVI's little endian. */
420437
pjmedia_avi_swap_data(&avi_hdr.strl_hdr[i], sizeof(strl_hdr_t), 32);
@@ -434,7 +451,7 @@ pjmedia_avi_writer_create_streams(pj_pool_t *pool_,
434451
goto on_error;
435452

436453
/* Write headers. */
437-
status = write_headers(streams);
454+
status = write_headers(streams->fd, streams);
438455
if (status != PJ_SUCCESS)
439456
goto on_error;
440457

0 commit comments

Comments
 (0)