Skip to content

Commit 9d2cb8b

Browse files
seven1240andywolk
authored andcommitted
[mod_av] play video without decode
1 parent 0db19ec commit 9d2cb8b

File tree

7 files changed

+896
-4
lines changed

7 files changed

+896
-4
lines changed
+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
test/test_BT7.mp4
2+
test/test_RGB.mp4
3+
test/test_packetizer

src/mod/applications/mod_av/Makefile.am

+5-2
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ endif
1313

1414
noinst_LTLIBRARIES = libavmod.la
1515

16-
libavmod_la_SOURCES = mod_av.c avformat.c avcodec.c
16+
libavmod_la_SOURCES = mod_av.c avformat.c avcodec.c switch_packetizer.c
1717
libavmod_la_CFLAGS = $(AM_CFLAGS) $(AVFORMAT_CFLAGS) $(AVCODEC_CFLAGS) $(SWSCALE_CFLAGS) $(AVUTIL_CFLAGS) $(RESAMPLE_CFLAGS)
1818

1919
mod_LTLIBRARIES = mod_av.la
@@ -22,13 +22,16 @@ mod_av_la_LIBADD = libavmod.la $(switch_builddir)/libfreeswitch.la $(AVFORMAT_
2222
mod_av_la_LDFLAGS = -avoid-version -module -no-undefined -shared -lm -lz
2323

2424

25-
noinst_PROGRAMS = test/test_mod_av test/test_avformat
25+
noinst_PROGRAMS = test/test_mod_av test/test_avformat test/test_packetizer
2626
test_test_mod_av_CFLAGS = $(SWITCH_AM_CFLAGS) -I../ -DSWITCH_TEST_BASE_DIR_FOR_CONF=\"${abs_builddir}/test\" -DSWITCH_TEST_BASE_DIR_OVERRIDE=\"${abs_builddir}/test\" $(AVFORMAT_CFLAGS) $(AVCODEC_CFLAGS) $(SWSCALE_CFLAGS) $(AVUTIL_CFLAGS) $(RESAMPLE_CFLAGS)
2727
test_test_mod_av_LDFLAGS = $(AVFORMAT_LIBS) $(AVCODEC_LIBS) $(SWSCALE_LIBS) $(AVUTIL_LIBS) $(RESAMPLE_LIBS) -avoid-version -no-undefined $(SWITCH_AM_LDFLAGS)
2828
test_test_mod_av_LDADD = libavmod.la $(switch_builddir)/libfreeswitch.la
2929
test_test_avformat_CFLAGS = $(SWITCH_AM_CFLAGS) -I../ -DSWITCH_TEST_BASE_DIR_FOR_CONF=\"${abs_builddir}/test\" -DSWITCH_TEST_BASE_DIR_OVERRIDE=\"${abs_builddir}/test\" $(AVFORMAT_CFLAGS) $(AVCODEC_CFLAGS) $(SWSCALE_CFLAGS) $(AVUTIL_CFLAGS) $(RESAMPLE_CFLAGS)
3030
test_test_avformat_LDFLAGS = $(AVFORMAT_LIBS) $(AVCODEC_LIBS) $(SWSCALE_LIBS) $(AVUTIL_LIBS) $(RESAMPLE_LIBS) -avoid-version -no-undefined $(SWITCH_AM_LDFLAGS)
3131
test_test_avformat_LDADD = libavmod.la $(switch_builddir)/libfreeswitch.la
32+
test_test_packetizer_CFLAGS = $(SWITCH_AM_CFLAGS) -I../ -DSWITCH_TEST_BASE_DIR_FOR_CONF=\"${abs_builddir}/test\" -DSWITCH_TEST_BASE_DIR_OVERRIDE=\"${abs_builddir}/test\" $(AVFORMAT_CFLAGS) $(AVCODEC_CFLAGS) $(SWSCALE_CFLAGS) $(AVUTIL_CFLAGS) $(RESAMPLE_CFLAGS)
33+
test_test_packetizer_LDFLAGS = $(AVFORMAT_LIBS) $(AVCODEC_LIBS) $(SWSCALE_LIBS) $(AVUTIL_LIBS) $(RESAMPLE_LIBS) -avoid-version -no-undefined $(SWITCH_AM_LDFLAGS)
34+
test_test_packetizer_LDADD = libavmod.la $(switch_builddir)/libfreeswitch.la
3235

3336
TESTS = $(noinst_PROGRAMS)
3437

src/mod/applications/mod_av/avformat.c

+143-2
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,9 @@ GCC_DIAG_OFF(deprecated-declarations)
5454
#include <libswresample/swresample.h>
5555
#endif
5656

57+
#include <switch_packetizer.h>
58+
#define SLICE_SIZE (SWITCH_DEFAULT_VIDEO_SIZE + 100)
59+
5760
GCC_DIAG_ON(deprecated-declarations)
5861
#define SCALE_FLAGS SWS_BICUBIC
5962
#define DFT_RECORD_OFFSET 0
@@ -116,8 +119,6 @@ typedef struct record_helper_s {
116119
uint64_t last_ts;
117120
} record_helper_t;
118121

119-
120-
121122
/* file interface */
122123

123124
struct av_file_context {
@@ -161,6 +162,11 @@ struct av_file_context {
161162

162163
switch_time_t last_vid_write;
163164
int audio_timer;
165+
166+
switch_bool_t no_video_decode;
167+
switch_queue_t *video_pkt_queue;
168+
switch_packetizer_t *packetizer;
169+
AVPacket *last_read_pkt;
164170
};
165171

166172
typedef struct av_file_context av_file_context_t;
@@ -772,6 +778,15 @@ static int flush_video_queue(switch_queue_t *q, int min)
772778
return switch_queue_size(q);
773779
}
774780

781+
static void flush_video_pkt_queue(switch_queue_t *q)
782+
{
783+
AVPacket *pkt;
784+
785+
while (switch_queue_trypop(q, (void **)&pkt) == SWITCH_STATUS_SUCCESS) {
786+
av_packet_unref(pkt);
787+
}
788+
}
789+
775790
static void *SWITCH_THREAD_FUNC video_thread_run(switch_thread_t *thread, void *obj)
776791
{
777792
av_file_context_t *context = (av_file_context_t *) obj;
@@ -1387,6 +1402,34 @@ GCC_DIAG_ON(deprecated-declarations)
13871402
if (context->has_video && pkt.stream_index == context->video_st.st->index) {
13881403
AVFrame *vframe;
13891404
switch_image_t *img;
1405+
1406+
if (context->no_video_decode) {
1407+
if (eof) {
1408+
break;
1409+
} else {
1410+
switch_status_t status;
1411+
AVPacket *new_pkt = malloc(sizeof(AVPacket));
1412+
1413+
if (0) { // debug
1414+
uint8_t *p = pkt.data;
1415+
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "size = %u %x %x %x %x %x %x\n", pkt.size, *p, *(p+1), *(p+2), *(p+3), *(p+4), *(p+5));
1416+
}
1417+
1418+
av_init_packet(new_pkt);
1419+
av_packet_ref(new_pkt, &pkt);
1420+
status = switch_queue_push(context->video_pkt_queue, new_pkt);
1421+
// switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "size = %4u flag=%x pts=%" SWITCH_INT64_T_FMT " dts=%" SWITCH_INT64_T_FMT "\n", pkt.size, pkt.flags, pkt.pts, pkt.dts);
1422+
1423+
context->vid_ready = 1;
1424+
if (status != SWITCH_STATUS_SUCCESS) {
1425+
av_packet_unref(new_pkt);
1426+
free(new_pkt);
1427+
}
1428+
av_packet_unref(&pkt);
1429+
continue;
1430+
}
1431+
}
1432+
13901433
if (!sync) {
13911434
switch_buffer_zero(context->audio_buffer);
13921435
sync = 1;
@@ -1680,6 +1723,11 @@ static switch_status_t av_file_open(switch_file_handle_t *handle, const char *pa
16801723

16811724
if (context->has_video) {
16821725
switch_queue_create(&context->eh.video_queue, context->read_fps, handle->memory_pool);
1726+
context->no_video_decode = handle->params && switch_true(switch_event_get_header(handle->params, "no_video_decode"));
1727+
if (context->no_video_decode) {
1728+
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Opening video in no decode mode\n");
1729+
switch_queue_create(&context->video_pkt_queue, 120 * 5, handle->memory_pool);
1730+
}
16831731
switch_mutex_init(&context->eh.mutex, SWITCH_MUTEX_NESTED, handle->memory_pool);
16841732
switch_core_timer_init(&context->video_timer, "soft", (int)(1000.0f / context->read_fps), 1, context->pool);
16851733
}
@@ -2177,6 +2225,15 @@ static switch_status_t av_file_close(switch_file_handle_t *handle)
21772225
context->file_read_thread_running = 0;
21782226
}
21792227

2228+
if (context->video_pkt_queue) {
2229+
flush_video_pkt_queue(context->video_pkt_queue);
2230+
switch_queue_term(context->video_pkt_queue);
2231+
}
2232+
2233+
if (context->packetizer) {
2234+
switch_packetizer_close(&context->packetizer);
2235+
}
2236+
21802237
if (context->file_read_thread) {
21812238
switch_thread_join(&status, context->file_read_thread);
21822239
context->file_read_thread = NULL;
@@ -2249,6 +2306,7 @@ static switch_status_t av_file_read(switch_file_handle_t *handle, void *data, si
22492306
}
22502307

22512308
switch_mutex_lock(context->mutex);
2309+
22522310
while (!context->file_read_thread_started) {
22532311
switch_thread_cond_wait(context->cond, context->mutex);
22542312
}
@@ -2334,6 +2392,82 @@ static switch_status_t av_file_read_video(switch_file_handle_t *handle, switch_f
23342392
}
23352393
#else
23362394

2395+
static switch_status_t no_video_decode_packets(switch_file_handle_t *handle, switch_frame_t *frame, switch_video_read_flag_t flags)
2396+
{
2397+
av_file_context_t *context = (av_file_context_t *)handle->private_info;
2398+
MediaStream *mst = &context->video_st;
2399+
AVStream *st = mst->st;
2400+
// AVCodecContext *ctx = st->codec;
2401+
// int ticks = 0;
2402+
// int64_t max_delta = 1 * AV_TIME_BASE; // 1 second
2403+
switch_status_t status = SWITCH_STATUS_SUCCESS;
2404+
AVPacket *pkt;
2405+
int64_t pts;
2406+
2407+
2408+
if (!context->packetizer) {
2409+
// uint8_t *p = st->codecpar->extradata;
2410+
// switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "size = %u %x %x %x %x %x %x\n", st->codecpar->extradata_size, *p, *(p+1), *(p+2), *(p+3), *(p+4), *(p+5));
2411+
2412+
context->packetizer = switch_packetizer_create(SPT_H264_SIZED_BITSTREAM, SLICE_SIZE);
2413+
if (!context->packetizer) return SWITCH_STATUS_FALSE;
2414+
2415+
switch_packetizer_feed_extradata(context->packetizer, st->codecpar->extradata, st->codecpar->extradata_size);
2416+
}
2417+
2418+
if (context->last_read_pkt) {
2419+
status = switch_packetizer_read(context->packetizer, frame);
2420+
if (status == SWITCH_STATUS_SUCCESS) {
2421+
av_packet_unref(context->last_read_pkt);
2422+
free(context->last_read_pkt);
2423+
context->last_read_pkt = NULL;
2424+
}
2425+
return status;
2426+
}
2427+
2428+
status = switch_queue_trypop(context->video_pkt_queue, (void **)&pkt);
2429+
2430+
if (status != SWITCH_STATUS_SUCCESS || !pkt) {
2431+
switch_cond_next();
2432+
return SWITCH_STATUS_BREAK;
2433+
}
2434+
2435+
context->last_read_pkt = pkt;
2436+
status = switch_packetizer_feed(context->packetizer, pkt->data, pkt->size);
2437+
status = switch_packetizer_read(context->packetizer, frame);
2438+
pts = av_rescale_q(pkt->pts, st->time_base, AV_TIME_BASE_Q);
2439+
frame->timestamp = pts * 9 / 100; // scale to sample 900000
2440+
// switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "pts=%" SWITCH_INT64_T_FMT " status = %d\n", pts, status);
2441+
2442+
if (status == SWITCH_STATUS_SUCCESS) {
2443+
av_packet_unref(context->last_read_pkt);
2444+
free(context->last_read_pkt);
2445+
context->last_read_pkt = NULL;
2446+
}
2447+
2448+
2449+
if (status == SWITCH_STATUS_SUCCESS || status == SWITCH_STATUS_MORE_DATA) {
2450+
if (!context->video_start_time) {
2451+
context->video_start_time = switch_time_now() - pts;
2452+
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "set start time: %" SWITCH_INT64_T_FMT " now: %" SWITCH_INT64_T_FMT " pts: %" SWITCH_INT64_T_FMT "\n", context->video_start_time, switch_time_now(), pts);
2453+
} else if (flags & SVR_BLOCK) {
2454+
int64_t sleep = pts - (switch_time_now() - context->video_start_time);
2455+
if (sleep > 0) {
2456+
// switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "zzZ... %" SWITCH_INT64_T_FMT "\n", sleep);
2457+
if (sleep > 1000000) {
2458+
sleep = 1000000;
2459+
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "but zzZ... %" SWITCH_INT64_T_FMT " at most\n", sleep);
2460+
}
2461+
switch_yield(sleep);
2462+
} else {
2463+
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "video is late %" SWITCH_INT64_T_FMT "\n", sleep);
2464+
}
2465+
}
2466+
}
2467+
2468+
return status;
2469+
}
2470+
23372471
static switch_status_t av_file_read_video(switch_file_handle_t *handle, switch_frame_t *frame, switch_video_read_flag_t flags)
23382472
{
23392473
av_file_context_t *context = (av_file_context_t *)handle->private_info;
@@ -2353,6 +2487,13 @@ static switch_status_t av_file_read_video(switch_file_handle_t *handle, switch_f
23532487
return SWITCH_STATUS_BREAK;
23542488
}
23552489

2490+
if (context->no_video_decode) {
2491+
switch_set_flag(frame, SFF_ENCODED);
2492+
status = no_video_decode_packets(handle, frame, flags);
2493+
// switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "return len=%4u nalu=%02x m=%d ts=%u\n", frame->datalen, *(uint8_t *)frame->data, frame->m, frame->timestamp);
2494+
return status;
2495+
}
2496+
23562497
if (handle->mm.fps > 0 && handle->mm.fps < smaller_ts) {
23572498
smaller_ts = handle->mm.fps;
23582499
}

0 commit comments

Comments
 (0)