diff --git a/CHANGELOG.md b/CHANGELOG.md index 1e6793117..f3e67f033 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## Changelog for 24.04 * dpdk: upgrade dpdk version to 23.11. +* st22: add interlaced support. ## Changelog for 23.12 diff --git a/app/sample/rx_st22_pipeline_sample.c b/app/sample/rx_st22_pipeline_sample.c index 3c6d79677..b644e5132 100644 --- a/app/sample/rx_st22_pipeline_sample.c +++ b/app/sample/rx_st22_pipeline_sample.c @@ -167,6 +167,7 @@ int main(int argc, char** argv) { ops_rx.width = ctx.width; ops_rx.height = ctx.height; ops_rx.fps = ctx.fps; + ops_rx.interlaced = ctx.interlaced; ops_rx.output_fmt = ctx.output_fmt; ops_rx.pack_type = ST22_PACK_CODESTREAM; ops_rx.codec = ctx.st22p_codec; diff --git a/app/sample/tx_st22_pipeline_sample.c b/app/sample/tx_st22_pipeline_sample.c index 544c7ff54..17a42942c 100644 --- a/app/sample/tx_st22_pipeline_sample.c +++ b/app/sample/tx_st22_pipeline_sample.c @@ -229,6 +229,7 @@ int main(int argc, char** argv) { ops_tx.width = ctx.width; ops_tx.height = ctx.height; ops_tx.fps = ctx.fps; + ops_tx.interlaced = ctx.interlaced; ops_tx.input_fmt = ctx.input_fmt; ops_tx.pack_type = ST22_PACK_CODESTREAM; ops_tx.codec = ctx.st22p_codec; @@ -236,6 +237,7 @@ int main(int argc, char** argv) { ops_tx.quality = ST22_QUALITY_MODE_QUALITY; ops_tx.codec_thread_cnt = 2; ops_tx.codestream_size = ops_tx.width * ops_tx.height * bpp / 8; + if (ops_tx.interlaced) ops_tx.codestream_size /= 2; ops_tx.framebuff_cnt = ctx.framebuff_cnt; ops_tx.notify_frame_available = tx_st22p_frame_available; diff --git a/app/src/parse_json.c b/app/src/parse_json.c index 29e506596..505890dbb 100644 --- a/app/src/parse_json.c +++ b/app/src/parse_json.c @@ -1166,6 +1166,13 @@ static int parse_st22p_fps(json_object* st22p_obj, st_json_st22p_session_t* st22 return ST_JSON_SUCCESS; } +static int parse_st22p_interlace(json_object* st22p_obj, st_json_st22p_session_t* st22p) { + json_object* obj = st_json_object_object_get(st22p_obj, "interlaced"); + if (!obj) return ST_JSON_SUCCESS; + st22p->info.interlaced = json_object_get_boolean(obj); + return ST_JSON_SUCCESS; +} + static int parse_st22p_pack_type(json_object* st22p_obj, st_json_st22p_session_t* st22p) { const char* pack_type = json_object_get_string(st_json_object_object_get(st22p_obj, "pack_type")); @@ -1312,6 +1319,10 @@ static int st_json_parse_tx_st22p(int idx, json_object* st22p_obj, ret = parse_st22p_fps(st22p_obj, st22p); if (ret < 0) return ret; + /* parse interlace */ + ret = parse_st22p_interlace(st22p_obj, st22p); + if (ret < 0) return ret; + /* parse pack_type */ ret = parse_st22p_pack_type(st22p_obj, st22p); if (ret < 0) return ret; @@ -1382,6 +1393,10 @@ static int st_json_parse_rx_st22p(int idx, json_object* st22p_obj, ret = parse_st22p_fps(st22p_obj, st22p); if (ret < 0) return ret; + /* parse interlace */ + ret = parse_st22p_interlace(st22p_obj, st22p); + if (ret < 0) return ret; + /* parse pack_type */ ret = parse_st22p_pack_type(st22p_obj, st22p); if (ret < 0) return ret; diff --git a/app/src/parse_json.h b/app/src/parse_json.h index 4f82f6708..1dcd28a1c 100644 --- a/app/src/parse_json.h +++ b/app/src/parse_json.h @@ -181,6 +181,7 @@ typedef struct st_json_st22p_info { uint32_t width; uint32_t height; enum st_fps fps; + bool interlaced; enum st_plugin_device device; enum st22_codec codec; enum st22_pack_type pack_type; diff --git a/app/src/rx_st20p_app.c b/app/src/rx_st20p_app.c index 415cacc4e..06df90b4d 100644 --- a/app/src/rx_st20p_app.c +++ b/app/src/rx_st20p_app.c @@ -31,6 +31,10 @@ static void app_rx_st20p_consume_frame(struct st_app_rx_st20p_session* s, frame->pkts_recv[MTL_SESSION_PORT_R], frame->pkts_total); } + if (frame->interlaced) { + dbg("%s(%d), %s field\n", __func__, s->idx, frame->second_field ? "second" : "first"); + } + if (d && d->front_frame) { if (st_pthread_mutex_trylock(&d->display_frame_mutex) == 0) { if (frame->fmt == ST_FRAME_FMT_YUV422RFC4175PG2BE10) { diff --git a/app/src/rx_st22p_app.c b/app/src/rx_st22p_app.c index 88dbe4e17..32d2cfac0 100644 --- a/app/src/rx_st22p_app.c +++ b/app/src/rx_st22p_app.c @@ -18,6 +18,10 @@ static void app_rx_st22p_consume_frame(struct st_app_rx_st22p_session* s, struct st_frame* frame) { struct st_display* d = s->display; + if (frame->interlaced) { + dbg("%s(%d), %s field\n", __func__, s->idx, frame->second_field ? "second" : "first"); + } + if (d && d->front_frame) { if (st_pthread_mutex_trylock(&d->display_frame_mutex) == 0) { if (frame->fmt == ST_FRAME_FMT_UYVY) @@ -163,6 +167,7 @@ static int app_rx_st22p_init(struct st_app_context* ctx, ops.width = st22p ? st22p->info.width : 1920; ops.height = st22p ? st22p->info.height : 1080; ops.fps = st22p ? st22p->info.fps : ST_FPS_P59_94; + ops.interlaced = st22p ? st22p->info.interlaced : false; ops.output_fmt = st22p ? st22p->info.format : ST_FRAME_FMT_YUV422RFC4175PG2BE10; ops.port.payload_type = st22p ? st22p->base.payload_type : ST_APP_PAYLOAD_TYPE_ST22; ops.pack_type = st22p ? st22p->info.pack_type : ST22_PACK_CODESTREAM; diff --git a/app/src/tx_st20p_app.c b/app/src/tx_st20p_app.c index 00bbd5559..eb9258009 100644 --- a/app/src/tx_st20p_app.c +++ b/app/src/tx_st20p_app.c @@ -62,6 +62,10 @@ static void app_tx_st20p_build_frame(struct st_app_tx_st20p_session* s, /* point to next frame */ s->st20p_frame_cursor += s->st20p_frame_size; + if (frame->interlaced) { + dbg("%s(%d), %s field\n", __func__, s->idx, frame->second_field ? "second" : "first"); + } + app_tx_st20p_display_frame(s, frame); } diff --git a/app/src/tx_st22p_app.c b/app/src/tx_st22p_app.c index c7a33982e..50c327e7a 100644 --- a/app/src/tx_st22p_app.c +++ b/app/src/tx_st22p_app.c @@ -48,6 +48,10 @@ static void app_tx_st22p_build_frame(struct st_app_tx_st22p_session* s, /* point to next frame */ s->st22p_frame_cursor += s->st22p_frame_size; + if (frame->interlaced) { + dbg("%s(%d), %s field\n", __func__, s->idx, frame->second_field ? "second" : "first"); + } + app_tx_st22p_display_frame(s, frame); } @@ -239,6 +243,7 @@ static int app_tx_st22p_init(struct st_app_context* ctx, st_json_st22p_session_t ops.width = st22p ? st22p->info.width : 1920; ops.height = st22p ? st22p->info.height : 1080; ops.fps = st22p ? st22p->info.fps : ST_FPS_P59_94; + ops.interlaced = st22p ? st22p->info.interlaced : false; ops.input_fmt = st22p ? st22p->info.format : ST_FRAME_FMT_YUV422RFC4175PG2BE10; ops.pack_type = st22p ? st22p->info.pack_type : ST22_PACK_CODESTREAM; ops.codec = st22p ? st22p->info.codec : ST22_CODEC_JPEGXS; @@ -246,6 +251,7 @@ static int app_tx_st22p_init(struct st_app_context* ctx, st_json_st22p_session_t ops.quality = st22p ? st22p->info.quality : ST22_QUALITY_MODE_SPEED; ops.codec_thread_cnt = st22p ? st22p->info.codec_thread_count : 0; ops.codestream_size = ops.width * ops.height * 3 / 8; + if (ops.interlaced) ops.codestream_size /= 2; /* the size is for each field */ ops.framebuff_cnt = 2; ops.notify_frame_available = app_tx_st22p_frame_available; if (st22p && st22p->enable_rtcp) ops.flags |= ST22P_TX_FLAG_ENABLE_RTCP; diff --git a/app/src/tx_video_app.c b/app/src/tx_video_app.c index eb7f250bd..4b00e7ab5 100644 --- a/app/src/tx_video_app.c +++ b/app/src/tx_video_app.c @@ -298,6 +298,7 @@ static void* app_tx_video_pcap_thread(void* arg) { } udp_data_len = 0; packet = (uint8_t*)pcap_next(s->st20_pcap, &hdr); + dbg("%s(%d), packet %p\n", __func__, idx, packet); if (packet) { eth_hdr = (struct ether_header*)packet; if (ntohs(eth_hdr->ether_type) == ETHERTYPE_IP) { @@ -306,6 +307,7 @@ static void* app_tx_video_pcap_thread(void* arg) { udp_hdr = (struct udphdr*)(packet + sizeof(struct ether_header) + sizeof(struct ip)); udp_data_len = ntohs(udp_hdr->len) - sizeof(struct udphdr); + dbg("%s(%d), packet %p udp_data_len %u\n", __func__, idx, packet, udp_data_len); mtl_memcpy(usrptr, packet + sizeof(struct ether_header) + sizeof(struct ip) + sizeof(struct udphdr), @@ -324,7 +326,12 @@ static void* app_tx_video_pcap_thread(void* arg) { } struct st_rfc3550_rtp_hdr* hdr = (struct st_rfc3550_rtp_hdr*)usrptr; - if (hdr->payload_type != s->payload_type) udp_data_len = 0; + if (hdr->payload_type != s->payload_type) { + udp_data_len = 0; + err("%s(%d), expect payload_type %u but pcap is %u, please correct the " + "payload_type in json\n", + __func__, idx, s->payload_type, hdr->payload_type); + } st20_tx_put_mbuf(s->handle, mbuf, udp_data_len); diff --git a/include/st20_api.h b/include/st20_api.h index b89a0c89b..2303e5eba 100644 --- a/include/st20_api.h +++ b/include/st20_api.h @@ -499,6 +499,8 @@ struct st22_tx_frame_meta { uint32_t height; /** Frame resolution fps, set by lib */ enum st_fps fps; + /** Second field type indicate, for interlaced mode */ + bool second_field; /** codestream_size for next_frame_idx, set by user */ size_t codestream_size; /** Timestamp format, user can customize it if ST22_TX_FLAG_USER_PACING */ @@ -513,6 +515,8 @@ struct st22_tx_frame_meta { * Frame meta data of st2110-22(video) rx streaming */ struct st22_rx_frame_meta { + /** Second field type indicate, for interlaced mode */ + bool second_field; /** Frame timestamp format */ enum st10_timestamp_fmt tfmt; /** Frame timestamp value */ @@ -572,7 +576,8 @@ MTL_PACK(struct st22_rfc9134_rtp_hdr { struct st_rfc3550_rtp_hdr base; /** F counter high part */ uint8_t f_counter_hi : 3; - /** Interlaced information */ + /** Interlaced information, 0b00: progressively, 0b10: first field, 0b11: second field. + */ uint8_t interlaced : 2; /** Last */ uint8_t last_packet : 1; @@ -975,6 +980,8 @@ struct st20_tx_ops { uint32_t height; /** Mandatory. Session resolution fps */ enum st_fps fps; + /** Mandatory. interlaced or not */ + bool interlaced; /** Mandatory. Session resolution format */ enum st20_fmt fmt; /** Mandatory. 7 bits payload type defined in RFC3550 */ @@ -990,13 +997,6 @@ struct st20_tx_ops { /** Optional. Flags to control session behaviors. See ST20_TX_FLAG_* for possible value */ uint32_t flags; - /** Optional. - * interlace or not, false(default): non-interlaced: true: interlaced. - * Ex for format 1080i50, please refer to below parameter configurations: - * interlaced: true, width: 1920, height: 1080, fps: ST_FPS_P50 - * and filled each frame(field) with 540 lines. - */ - bool interlaced; /** * Mandatory for ST20_TYPE_FRAME_LEVEL/ST20_TYPE_SLICE_LEVEL. @@ -1121,6 +1121,8 @@ struct st22_tx_ops { uint32_t height; /** Mandatory. Session resolution fps */ enum st_fps fps; + /** Mandatory. interlaced or not */ + bool interlaced; /** Mandatory. Session resolution format */ enum st20_fmt fmt; /** Mandatory. 7 bits payload type define in RFC3550 */ @@ -1292,6 +1294,8 @@ struct st20_rx_ops { uint32_t height; /** Mandatory. Session resolution fps */ enum st_fps fps; + /** Mandatory. interlaced or not */ + bool interlaced; /** Mandatory. Session resolution format */ enum st20_fmt fmt; /** Mandatory. 7 bits payload type define in RFC3550 */ @@ -1312,13 +1316,6 @@ struct st20_rx_ops { /** Optional. Flags to control session behaviors. See ST20_RX_FLAG_* for possible value */ uint32_t flags; - /** Optional. - * interlace or not, false(default): non-interlaced: true: interlaced. - * Ex for format 1080i50, please refer to below parameter configurations: - * interlaced: true, width: 1920, height: 1080, fps: ST_FPS_P50 - * and each frame(field) received has 540 lines data. - */ - bool interlaced; /** * Mandatory for ST20_TYPE_FRAME_LEVEL/ST20_TYPE_SLICE_LEVEL. @@ -1443,6 +1440,8 @@ struct st22_rx_ops { uint32_t height; /** Mandatory. Session resolution fps */ enum st_fps fps; + /** Mandatory. interlaced or not */ + bool interlaced; /** Mandatory. Session resolution format */ enum st20_fmt fmt; /** Mandatory. 7 bits payload type define in RFC3550 */ diff --git a/include/st_pipeline_api.h b/include/st_pipeline_api.h index 7e8b3cc2d..ad3b6adf3 100644 --- a/include/st_pipeline_api.h +++ b/include/st_pipeline_api.h @@ -551,6 +551,8 @@ struct st22_encoder_create_req { uint32_t height; /** Session resolution fps, set by lib */ enum st_fps fps; + /** Interlaced or not, set by lib */ + bool interlaced; /** Session input frame format, set by lib */ enum st_frame_fmt input_fmt; /** Session output frame format, set by lib */ @@ -606,6 +608,8 @@ struct st22_decoder_create_req { uint32_t height; /** Session resolution fps, set by lib */ enum st_fps fps; + /** Interlaced or not, set by lib */ + bool interlaced; /** Session input frame format, set by lib */ enum st_frame_fmt input_fmt; /** Session output frame format, set by lib */ @@ -640,9 +644,9 @@ struct st22_decoder_dev { /** The structure info for st22 decode frame meta. */ struct st22_decode_frame_meta { - /** Encode source frame */ + /** Decode source frame */ struct st_frame* src; - /** Encode dst frame */ + /** Decode dst frame */ struct st_frame* dst; /** priv pointer for lib, do not touch this */ void* priv; @@ -743,6 +747,8 @@ struct st20p_tx_ops { uint32_t height; /** Mandatory. Session resolution fps */ enum st_fps fps; + /** Mandatory. interlaced or not */ + bool interlaced; /** Mandatory. Session input frame format */ enum st_frame_fmt input_fmt; /** Mandatory. Session transport pacing type */ @@ -778,13 +784,7 @@ struct st20p_tx_ops { * tasklet routine. */ int (*notify_frame_done)(void* priv, struct st_frame* frame); - /** Optional. - * interlace or not, false(default): non-interlaced: true: interlaced. - * Ex for format 1080i50, please refer to below parameter configurations: - * interlaced: true, width: 1920, height: 1080, fps: ST_FPS_P50 - * and filled each frame(field) with 540 lines. - */ - bool interlaced; + /** Optional. Linesize for transport frame, only for non-convert mode */ size_t transport_linesize; @@ -836,6 +836,8 @@ struct st20p_rx_ops { uint32_t height; /** Mandatory. Session resolution fps */ enum st_fps fps; + /** Mandatory. interlaced or not */ + bool interlaced; /** Mandatory. Session transport frame format */ enum st20_fmt transport_fmt; /** Mandatory. Session output frame format */ @@ -862,13 +864,6 @@ struct st20p_rx_ops { */ int (*notify_frame_available)(void* priv); - /** Optional. - * interlace or not, false(default): non-interlaced: true: interlaced. - * Ex for format 1080i50, please refer to below parameter configurations: - * interlaced: true, width: 1920, height: 1080, fps: ST_FPS_P50 - * and each frame(field) received has 540 lines data. - */ - bool interlaced; /** Optional. Linesize for transport frame, only for non-convert mode */ size_t transport_linesize; /** Optional. Array of external frames */ @@ -901,6 +896,8 @@ struct st22p_tx_ops { uint32_t height; /** Mandatory. Session resolution fps */ enum st_fps fps; + /** Mandatory. interlaced or not */ + bool interlaced; /** Mandatory. Session input frame format */ enum st_frame_fmt input_fmt; /** Mandatory. packetization modes define in RFC9134 */ @@ -911,7 +908,8 @@ struct st22p_tx_ops { enum st_plugin_device device; /** Mandatory. speed or quality mode */ enum st22_quality_mode quality; - /** Mandatory. codestream size, calculate as compress ratio */ + /** Mandatory. codestream size, calculate as compress ratio. For interlaced, it's the + * expected codestream size for each field */ size_t codestream_size; /** * Mandatory. the frame buffer count requested for one st22 pipeline tx session, @@ -967,6 +965,8 @@ struct st22p_rx_ops { uint32_t height; /** Mandatory. Session resolution fps */ enum st_fps fps; + /** Mandatory. interlaced or not */ + bool interlaced; /** Mandatory. Session output frame format */ enum st_frame_fmt output_fmt; /** Mandatory. packetization modes define in RFC9134 */ @@ -990,7 +990,8 @@ struct st22p_rx_ops { uint32_t flags; /** Optional. thread count for codec, leave to zero if not know */ uint32_t codec_thread_cnt; - /** Optional. max codestream size, lib will use output frame size if not set */ + /** Optional. max codestream size, lib will use output frame size if not set. For + * interlaced, it's the expected codestream size for each field */ size_t max_codestream_size; /** Optional for ST22P_RX_FLAG_ENABLE_RTCP. RTCP info */ struct st_rx_rtcp_ops* rtcp; diff --git a/lib/src/st2110/pipeline/st20_pipeline_tx.c b/lib/src/st2110/pipeline/st20_pipeline_tx.c index 75516396c..f9bdabf08 100644 --- a/lib/src/st2110/pipeline/st20_pipeline_tx.c +++ b/lib/src/st2110/pipeline/st20_pipeline_tx.c @@ -481,7 +481,7 @@ struct st_frame* st20p_tx_get_frame(st20p_tx_handle handle) { dbg("%s(%d), frame %u succ\n", __func__, idx, framebuff->idx); struct st_frame* frame = tx_st20p_user_frame(ctx, framebuff); - if (ctx->ops.interlaced) { /* init second_field but user still can customize also */ + if (ctx->ops.interlaced) { /* init second_field but user still can customize */ frame->second_field = ctx->second_field; ctx->second_field = ctx->second_field ? false : true; } @@ -527,6 +527,10 @@ int st20p_tx_put_frame(st20p_tx_handle handle, struct st_frame* frame) { framebuff->user_meta_data_size = frame->user_meta_size; } + if (ctx->ops.interlaced) { /* update second_field */ + framebuff->dst.second_field = framebuff->src.second_field = frame->second_field; + } + if (ctx->internal_converter) { /* convert internal */ ctx->internal_converter->convert_func(&framebuff->src, &framebuff->dst); framebuff->stat = ST20P_TX_FRAME_CONVERTED; @@ -565,6 +569,10 @@ int st20p_tx_put_ext_frame(st20p_tx_handle handle, struct st_frame* frame, return -EIO; } + if (ctx->ops.interlaced) { /* update second_field */ + framebuff->dst.second_field = framebuff->src.second_field = frame->second_field; + } + uint8_t planes = st_frame_fmt_planes(framebuff->src.fmt); if (ctx->derive) { struct st20_ext_frame trans_ext_frame; diff --git a/lib/src/st2110/pipeline/st22_pipeline_rx.c b/lib/src/st2110/pipeline/st22_pipeline_rx.c index 71a11aacf..c85224108 100644 --- a/lib/src/st2110/pipeline/st22_pipeline_rx.c +++ b/lib/src/st2110/pipeline/st22_pipeline_rx.c @@ -100,6 +100,9 @@ static int rx_st22p_frame_ready(void* priv, void* frame, /* set dst timestamp to same as src? */ framebuff->dst.timestamp = meta->timestamp; + /* if second field */ + framebuff->dst.second_field = framebuff->src.second_field = meta->second_field; + framebuff->src.pkts_total = framebuff->dst.pkts_total = meta->pkts_total; for (enum mtl_session_port s_port = MTL_SESSION_PORT_P; s_port < MTL_SESSION_PORT_MAX; s_port++) { @@ -251,6 +254,7 @@ static int rx_st22p_create_transport(struct mtl_main_impl* impl, struct st22p_rx ops_rx.width = ops->width; ops_rx.height = ops->height; ops_rx.fps = ops->fps; + ops_rx.interlaced = ops->interlaced; ops_rx.payload_type = ops->port.payload_type; ops_rx.ssrc = ops->port.ssrc; ops_rx.type = ST22_TYPE_FRAME_LEVEL; @@ -272,6 +276,7 @@ static int rx_st22p_create_transport(struct mtl_main_impl* impl, struct st22p_rx frames[i].src.fmt = ctx->decode_impl->req.req.input_fmt; frames[i].src.buffer_size = ops_rx.framebuff_max_size; frames[i].src.data_size = ops_rx.framebuff_max_size; + frames[i].src.interlaced = ops->interlaced; frames[i].src.width = ops->width; frames[i].src.height = ops->height; frames[i].src.priv = &frames[i]; @@ -321,6 +326,7 @@ static int rx_st22p_init_dst_fbs(struct mtl_main_impl* impl, struct st22p_rx_ctx frames[i].stat = ST22P_RX_FRAME_FREE; frames[i].idx = i; frames[i].dst.fmt = ops->output_fmt; + frames[i].dst.interlaced = ops->interlaced; frames[i].dst.buffer_size = dst_size; frames[i].dst.data_size = dst_size; frames[i].dst.width = ops->width; @@ -471,7 +477,7 @@ st22p_rx_handle st22p_rx_create(mtl_handle mt, struct st22p_rx_ops* ops) { } } - dst_size = st_frame_size(ops->output_fmt, ops->width, ops->height, false); + dst_size = st_frame_size(ops->output_fmt, ops->width, ops->height, ops->interlaced); if (!dst_size) { err("%s(%d), get dst size fail\n", __func__, idx); return NULL; diff --git a/lib/src/st2110/pipeline/st22_pipeline_tx.c b/lib/src/st2110/pipeline/st22_pipeline_tx.c index 56e5f5d0b..46c9878b1 100644 --- a/lib/src/st2110/pipeline/st22_pipeline_tx.c +++ b/lib/src/st2110/pipeline/st22_pipeline_tx.c @@ -63,6 +63,8 @@ static int tx_st22p_next_frame(void* priv, uint16_t* next_frame_idx, framebuff->stat = ST22P_TX_FRAME_IN_TRANSMITTING; *next_frame_idx = framebuff->idx; + + meta->second_field = framebuff->src.second_field; if (ctx->ops.flags & (ST22P_TX_FLAG_USER_PACING | ST22P_TX_FLAG_USER_TIMESTAMP)) { meta->tfmt = framebuff->src.tfmt; meta->timestamp = framebuff->src.timestamp; @@ -257,6 +259,7 @@ static int tx_st22p_create_transport(struct mtl_main_impl* impl, struct st22p_tx ops_tx.width = ops->width; ops_tx.height = ops->height; ops_tx.fps = ops->fps; + ops_tx.interlaced = ops->interlaced; ops_tx.payload_type = ops->port.payload_type; ops_tx.ssrc = ops->port.ssrc; ops_tx.type = ST22_TYPE_FRAME_LEVEL; @@ -281,6 +284,7 @@ static int tx_st22p_create_transport(struct mtl_main_impl* impl, struct st22p_tx for (uint16_t i = 0; i < ctx->framebuff_cnt; i++) { frames[i].dst.addr[0] = st22_tx_get_fb_addr(transport, i); frames[i].dst.fmt = ctx->encode_impl->req.req.output_fmt; + frames[i].dst.interlaced = ops->interlaced; frames[i].dst.buffer_size = ops_tx.framebuff_max_size; frames[i].dst.data_size = ops_tx.framebuff_max_size; frames[i].dst.width = ops->width; @@ -332,6 +336,7 @@ static int tx_st22p_init_src_fbs(struct mtl_main_impl* impl, struct st22p_tx_ctx frames[i].stat = ST22P_TX_FRAME_FREE; frames[i].idx = i; frames[i].src.fmt = ops->input_fmt; + frames[i].src.interlaced = ops->interlaced; frames[i].src.buffer_size = src_size; frames[i].src.data_size = src_size; frames[i].src.width = ops->width; @@ -434,6 +439,10 @@ struct st_frame* st22p_tx_get_frame(st22p_tx_handle handle) { mt_pthread_mutex_unlock(&ctx->lock); dbg("%s(%d), frame %u succ\n", __func__, idx, framebuff->idx); + if (ctx->ops.interlaced) { /* init second_field but user still can customize */ + framebuff->dst.second_field = framebuff->src.second_field = ctx->second_field; + ctx->second_field = ctx->second_field ? false : true; + } return &framebuff->src; } @@ -459,6 +468,10 @@ int st22p_tx_put_frame(st22p_tx_handle handle, struct st_frame* frame) { return -EIO; } + if (ctx->ops.interlaced) { /* update second_field */ + framebuff->dst.second_field = framebuff->src.second_field = frame->second_field; + } + framebuff->stat = ST22P_TX_FRAME_READY; st22_encode_notify_frame_ready(ctx->encode_impl); dbg("%s(%d), frame %u succ\n", __func__, idx, producer_idx); @@ -507,6 +520,10 @@ int st22p_tx_put_ext_frame(st22p_tx_handle handle, struct st_frame* frame, return ret; } + if (ctx->ops.interlaced) { /* update second_field */ + framebuff->dst.second_field = framebuff->src.second_field = frame->second_field; + } + framebuff->stat = ST22P_TX_FRAME_READY; st22_encode_notify_frame_ready(ctx->encode_impl); @@ -535,7 +552,7 @@ st22p_tx_handle st22p_tx_create(mtl_handle mt, struct st22p_tx_ops* ops) { return NULL; } - src_size = st_frame_size(ops->input_fmt, ops->width, ops->height, false); + src_size = st_frame_size(ops->input_fmt, ops->width, ops->height, ops->interlaced); if (!src_size) { err("%s(%d), get source size fail\n", __func__, idx); return NULL; diff --git a/lib/src/st2110/pipeline/st22_pipeline_tx.h b/lib/src/st2110/pipeline/st22_pipeline_tx.h index 1156c865f..def85301e 100644 --- a/lib/src/st2110/pipeline/st22_pipeline_tx.h +++ b/lib/src/st2110/pipeline/st22_pipeline_tx.h @@ -46,6 +46,7 @@ struct st22p_tx_ctx { struct st22_encode_session_impl* encode_impl; bool ready; bool ext_frame; + bool second_field; size_t src_size; diff --git a/lib/src/st2110/st_fmt.c b/lib/src/st2110/st_fmt.c index d069b4cc7..9b611f891 100644 --- a/lib/src/st2110/st_fmt.c +++ b/lib/src/st2110/st_fmt.c @@ -555,6 +555,15 @@ int st_frame_sanity_check(struct st_frame* frame) { frame->data_size, frame->buffer_size); return -EINVAL; } + + /* check data size is enough */ + size_t least_sz = + st_frame_size(frame->fmt, frame->width, frame->height, frame->interlaced); + if (frame->data_size < least_sz) { + err("%s, frame data size %" PRIu64 " small then frame least_sz %" PRIu64 "\n", + __func__, frame->data_size, least_sz); + return -EINVAL; + } } return 0; diff --git a/lib/src/st2110/st_header.h b/lib/src/st2110/st_header.h index ad8f57a5a..eb3c6e03a 100644 --- a/lib/src/st2110/st_header.h +++ b/lib/src/st2110/st_header.h @@ -390,6 +390,9 @@ struct st_tx_video_session_impl { uint32_t stat_max_notify_frame_us; uint32_t stat_unrecoverable_error; uint32_t stat_recoverable_error; + /* interlace */ + uint32_t stat_interlace_first_field; + uint32_t stat_interlace_second_field; }; struct st_tx_video_sessions_mgr { @@ -703,7 +706,10 @@ struct st_rx_video_session_impl { int stat_pkts_offset_dropped; int stat_pkts_out_of_order; int stat_pkts_redundant_dropped; - int stat_pkts_wrong_hdr_dropped; + int stat_pkts_wrong_pt_dropped; + int stat_pkts_wrong_ssrc_dropped; + int stat_pkts_wrong_kmod_dropped; /* for st22 */ + int stat_pkts_wrong_interlace_dropped; int stat_pkts_wrong_len_dropped; int stat_pkts_received; int stat_pkts_retransmit; @@ -730,6 +736,11 @@ struct st_rx_video_session_impl { uint32_t stat_slot_query_ext_fail; uint64_t stat_bytes_received; uint32_t stat_max_notify_frame_us; + /* for interlace */ + uint32_t stat_interlace_first_field; + uint32_t stat_interlace_second_field; + /* for st22 */ + uint32_t stat_st22_boxes; }; struct st_rx_video_sessions_mgr { @@ -946,7 +957,8 @@ struct st_rx_audio_session_impl { /* status */ int st30_stat_pkts_dropped; - int st30_stat_pkts_wrong_hdr_dropped; + int st30_stat_pkts_wrong_pt_dropped; + int st30_stat_pkts_wrong_ssrc_dropped; int st30_stat_pkts_len_mismatch_dropped; int st30_stat_pkts_received; int st30_stat_frames_dropped; @@ -1089,7 +1101,8 @@ struct st_rx_ancillary_session_impl { /* status */ rte_atomic32_t st40_stat_frames_received; int st40_stat_pkts_dropped; - int st40_stat_pkts_wrong_hdr_dropped; + int st40_stat_pkts_wrong_pt_dropped; + int st40_stat_pkts_wrong_ssrc_dropped; int st40_stat_pkts_received; uint64_t st40_stat_last_time; uint32_t stat_max_notify_rtp_us; diff --git a/lib/src/st2110/st_rx_ancillary_session.c b/lib/src/st2110/st_rx_ancillary_session.c index 052023cc2..e6c8d6e97 100644 --- a/lib/src/st2110/st_rx_ancillary_session.c +++ b/lib/src/st2110/st_rx_ancillary_session.c @@ -95,13 +95,17 @@ static int rx_ancillary_session_handle_pkt(struct mtl_main_impl* impl, MTL_MAY_UNUSED(s_port); if (payload_type != ops->payload_type) { - s->st40_stat_pkts_wrong_hdr_dropped++; + dbg("%s(%d,%d), get payload_type %u but expect %u\n", __func__, s->idx, s_port, + payload_type, ops->payload_type); + s->st40_stat_pkts_wrong_pt_dropped++; return -EINVAL; } if (ops->ssrc) { uint32_t ssrc = ntohl(rtp->ssrc); if (ssrc != ops->ssrc) { - s->st40_stat_pkts_wrong_hdr_dropped++; + dbg("%s(%d,%d), get ssrc %u but expect %u\n", __func__, s->idx, s_port, ssrc, + ops->ssrc); + s->st40_stat_pkts_wrong_ssrc_dropped++; return -EINVAL; } } @@ -347,7 +351,6 @@ static int rx_ancillary_session_attach(struct mtl_main_impl* impl, s->latest_seq_id = -1; s->st40_stat_pkts_received = 0; s->st40_stat_pkts_dropped = 0; - s->st40_stat_pkts_wrong_hdr_dropped = 0; s->st40_stat_last_time = mt_get_monotonic_time(); rte_atomic32_set(&s->st40_stat_frames_received, 0); @@ -395,10 +398,15 @@ static void rx_ancillary_session_stat(struct st_rx_ancillary_session_impl* s) { notice("RX_ANC_SESSION(%d): st40 dropped pkts %d\n", idx, s->st40_stat_pkts_dropped); s->st40_stat_pkts_dropped = 0; } - if (s->st40_stat_pkts_wrong_hdr_dropped) { - notice("RX_ANC_SESSION(%d): wrong hdr dropped pkts %d\n", idx, - s->st40_stat_pkts_wrong_hdr_dropped); - s->st40_stat_pkts_wrong_hdr_dropped = 0; + if (s->st40_stat_pkts_wrong_pt_dropped) { + notice("RX_ANC_SESSION(%d): wrong hdr payload_type dropped pkts %d\n", idx, + s->st40_stat_pkts_wrong_pt_dropped); + s->st40_stat_pkts_wrong_pt_dropped = 0; + } + if (s->st40_stat_pkts_wrong_ssrc_dropped) { + notice("RX_ANC_SESSION(%d): wrong hdr ssrc dropped pkts %d\n", idx, + s->st40_stat_pkts_wrong_ssrc_dropped); + s->st40_stat_pkts_wrong_ssrc_dropped = 0; } if (s->time_measure) { notice("RX_ANC_SESSION(%d): notify rtp max %uus\n", idx, s->stat_max_notify_rtp_us); diff --git a/lib/src/st2110/st_rx_audio_session.c b/lib/src/st2110/st_rx_audio_session.c index 346bb58db..83392928b 100644 --- a/lib/src/st2110/st_rx_audio_session.c +++ b/lib/src/st2110/st_rx_audio_session.c @@ -396,13 +396,17 @@ static int rx_audio_session_handle_frame_pkt(struct mtl_main_impl* impl, uint32_t pkt_len = mbuf->data_len - sizeof(struct st_rfc3550_audio_hdr); if (payload_type != ops->payload_type) { - s->st30_stat_pkts_wrong_hdr_dropped++; + dbg("%s(%d,%d), get payload_type %u but expect %u\n", __func__, s->idx, s_port, + payload_type, ops->payload_type); + s->st30_stat_pkts_wrong_pt_dropped++; return -EINVAL; } if (ops->ssrc) { uint32_t ssrc = ntohl(rtp->ssrc); if (ssrc != ops->ssrc) { - s->st30_stat_pkts_wrong_hdr_dropped++; + dbg("%s(%d,%d), get ssrc %u but expect %u\n", __func__, s->idx, s_port, ssrc, + ops->ssrc); + s->st30_stat_pkts_wrong_ssrc_dropped++; return -EINVAL; } } @@ -498,13 +502,17 @@ static int rx_audio_session_handle_rtp_pkt(struct mtl_main_impl* impl, uint8_t payload_type = rtp->payload_type; if (payload_type != ops->payload_type) { - s->st30_stat_pkts_wrong_hdr_dropped++; + dbg("%s(%d,%d), get payload_type %u but expect %u\n", __func__, s->idx, s_port, + payload_type, ops->payload_type); + s->st30_stat_pkts_wrong_pt_dropped++; return -EINVAL; } if (ops->ssrc) { uint32_t ssrc = ntohl(rtp->ssrc); if (ssrc != ops->ssrc) { - s->st30_stat_pkts_wrong_hdr_dropped++; + dbg("%s(%d,%d), get ssrc %u but expect %u\n", __func__, s->idx, s_port, ssrc, + ops->ssrc); + s->st30_stat_pkts_wrong_ssrc_dropped++; return -EINVAL; } } @@ -763,7 +771,6 @@ static int rx_audio_session_attach(struct mtl_main_impl* impl, s->latest_seq_id = -1; s->st30_stat_pkts_received = 0; s->st30_stat_pkts_dropped = 0; - s->st30_stat_pkts_wrong_hdr_dropped = 0; s->st30_stat_frames_dropped = 0; rte_atomic32_set(&s->st30_stat_frames_received, 0); s->st30_stat_last_time = mt_get_monotonic_time(); @@ -826,10 +833,15 @@ static void rx_audio_session_stat(struct st_rx_audio_sessions_mgr* mgr, s->st30_stat_frames_dropped = 0; s->st30_stat_pkts_dropped = 0; } - if (s->st30_stat_pkts_wrong_hdr_dropped) { - notice("RX_AUDIO_SESSION(%d,%d): wrong hdr dropped pkts %d\n", m_idx, idx, - s->st30_stat_pkts_wrong_hdr_dropped); - s->st30_stat_pkts_wrong_hdr_dropped = 0; + if (s->st30_stat_pkts_wrong_pt_dropped) { + notice("RX_AUDIO_SESSION(%d,%d): wrong hdr payload_type dropped pkts %d\n", m_idx, + idx, s->st30_stat_pkts_wrong_pt_dropped); + s->st30_stat_pkts_wrong_pt_dropped = 0; + } + if (s->st30_stat_pkts_wrong_ssrc_dropped) { + notice("RX_AUDIO_SESSION(%d,%d): wrong hdr ssrc dropped pkts %d\n", m_idx, idx, + s->st30_stat_pkts_wrong_ssrc_dropped); + s->st30_stat_pkts_wrong_ssrc_dropped = 0; } if (s->st30_stat_pkts_len_mismatch_dropped) { notice("RX_AUDIO_SESSION(%d,%d): pkt len mismatch dropped pkts %d\n", m_idx, idx, diff --git a/lib/src/st2110/st_rx_video_session.c b/lib/src/st2110/st_rx_video_session.c index ca8a8f8f1..69abd2a84 100644 --- a/lib/src/st2110/st_rx_video_session.c +++ b/lib/src/st2110/st_rx_video_session.c @@ -734,6 +734,12 @@ static void rv_frame_notify(struct st_rx_video_session_impl* s, meta->fpt = fpt_delta; meta->timestamp_last_pkt = mtl_ptp_read_time(rv_get_impl(s)); meta->second_field = slot->second_field; + if (ops->interlaced) { + if (slot->second_field) + s->stat_interlace_second_field++; + else + s->stat_interlace_first_field++; + } meta->frame_total_size = s->st20_frame_size; meta->uframe_total_size = s->st20_uframe_size; meta->frame_recv_size = rv_slot_get_frame_size(slot); @@ -804,6 +810,13 @@ static void rv_st22_frame_notify(struct st_rx_video_session_impl* s, struct st20_rx_ops* ops = &s->ops; struct st22_rx_frame_meta* meta = &slot->st22_meta; + meta->second_field = slot->second_field; + if (ops->interlaced) { + if (slot->second_field) + s->stat_interlace_second_field++; + else + s->stat_interlace_first_field++; + } meta->tfmt = ST10_TIMESTAMP_FMT_MEDIA_CLK; meta->timestamp = slot->tmstamp; meta->frame_total_size = rv_slot_get_frame_size(slot); @@ -1370,15 +1383,17 @@ static int rv_handle_frame_pkt(struct st_rx_video_session_impl* s, struct rte_mb line1_offset, line1_length); if (payload_type != ops->payload_type) { - s->stat_pkts_wrong_hdr_dropped++; + dbg("%s(%d,%d), get payload_type %u but expect %u\n", __func__, s->idx, s_port, + payload_type, ops->payload_type); + s->stat_pkts_wrong_pt_dropped++; return -EINVAL; } if (ops->ssrc) { uint32_t ssrc = ntohl(rtp->base.ssrc); - dbg("%s(%d,%d): expect ssrc %u actual %u\n", __func__, s->idx, s_port, ops->ssrc, - ssrc); + dbg("%s(%d,%d), get ssrc %u but expect %u\n", __func__, s->idx, s_port, ssrc, + ops->ssrc); if (ssrc != ops->ssrc) { - s->stat_pkts_wrong_hdr_dropped++; + s->stat_pkts_wrong_ssrc_dropped++; return -EINVAL; } } @@ -1623,14 +1638,17 @@ static int rv_handle_rtp_pkt(struct st_rx_video_session_impl* s, struct rte_mbuf int pkt_idx = -1; if (payload_type != ops->payload_type) { - dbg("%s, payload_type mismatch %d %d\n", __func__, payload_type, ops->payload_type); - s->stat_pkts_wrong_hdr_dropped++; + dbg("%s(%d,%d), get payload_type %u but expect %u\n", __func__, s->idx, s_port, + payload_type, ops->payload_type); + s->stat_pkts_wrong_pt_dropped++; return -EINVAL; } if (ops->ssrc) { uint32_t ssrc = ntohl(rtp->ssrc); if (ssrc != ops->ssrc) { - s->stat_pkts_wrong_hdr_dropped++; + dbg("%s(%d,%d), get ssrc %u but expect %u\n", __func__, s->idx, s_port, ssrc, + ops->ssrc); + s->stat_pkts_wrong_ssrc_dropped++; return -EINVAL; } } @@ -1733,13 +1751,17 @@ static int rv_parse_st22_boxes(struct st_rx_video_session_impl* s, void* boxes, } if ((jpvs_len + colr_len) > 512) { - info("%s(%d): err jpvs_len %u colr_len %u\n", __func__, s->idx, jpvs_len, colr_len); + err("%s(%d): err jpvs_len %u colr_len %u\n", __func__, s->idx, jpvs_len, colr_len); return -EIO; } slot->st22_box_hdr_length = jpvs_len + colr_len; dbg("%s(%d): st22_box_hdr_length %u\n", __func__, s->idx, slot->st22_box_hdr_length); + if (slot->st22_box_hdr_length) { + s->stat_st22_boxes++; + } + #if 0 uint8_t* buf = boxes - slot->st22_box_hdr_length; for (uint16_t i = 0; i < slot->st22_box_hdr_length; i++) { @@ -1773,22 +1795,41 @@ static int rv_handle_st22_pkt(struct st_rx_video_session_impl* s, struct rte_mbu int ret; if (payload_type != ops->payload_type) { - s->stat_pkts_wrong_hdr_dropped++; + dbg("%s(%d,%d), get payload_type %u but expect %u\n", __func__, s->idx, s_port, + payload_type, ops->payload_type); + s->stat_pkts_wrong_pt_dropped++; return -EINVAL; } if (ops->ssrc) { uint32_t ssrc = ntohl(rtp->base.ssrc); if (ssrc != ops->ssrc) { - s->stat_pkts_wrong_hdr_dropped++; + dbg("%s(%d,%d), get ssrc %u but expect %u\n", __func__, s->idx, s_port, ssrc, + ops->ssrc); + s->stat_pkts_wrong_ssrc_dropped++; return -EINVAL; } } - if (rtp->kmode) { - s->stat_pkts_wrong_hdr_dropped++; + if (rtp->kmode) { /* only pacKetization mode now */ + s->stat_pkts_wrong_kmod_dropped++; return -EINVAL; } + /* check interlace */ + if (s->ops.interlaced) { + if (!(rtp->interlaced & 0x2)) { + s->stat_pkts_wrong_interlace_dropped++; + return -EINVAL; + } + } else { + if (rtp->interlaced) { + s->stat_pkts_wrong_interlace_dropped++; + dbg("%s(%d,%d), rtp interlaced 0x%x set for progressive\n", __func__, s->idx, + s_port, rtp->interlaced); + return -EINVAL; + } + } + /* find the target slot by tmstamp */ bool exist_ts = false; struct st_rx_video_slot_impl* slot = rv_slot_by_tmstamp(s, tmstamp, NULL, &exist_ts); @@ -1803,6 +1844,8 @@ static int rv_handle_st22_pkt(struct st_rx_video_session_impl* s, struct rte_mbu } uint8_t* bitmap = slot->frame_bitmap; + slot->second_field = (rtp->interlaced == 0x3) ? true : false; + dbg("%s(%d,%d), seq_id %d kmode %u trans_order %u\n", __func__, s->idx, s_port, seq_id, rtp->kmode, rtp->trans_order); dbg("%s(%d,%d), seq_id %d p_counter %u sep_counter %u\n", __func__, s->idx, s_port, @@ -1810,7 +1853,7 @@ static int rv_handle_st22_pkt(struct st_rx_video_session_impl* s, struct rte_mbu if (slot->seq_id_got) { if (!rtp->base.marker && (payload_length != slot->st22_payload_length)) { - s->stat_pkts_wrong_hdr_dropped++; + s->stat_pkts_wrong_len_dropped++; return -EIO; } /* check if the same pks got already */ @@ -1934,13 +1977,17 @@ static int rv_handle_hdr_split_pkt(struct st_rx_video_session_impl* s, struct rte_mbuf* mbuf_next = mbuf->next; if (payload_type != ops->payload_type) { - s->stat_pkts_wrong_hdr_dropped++; + dbg("%s(%d,%d), get payload_type %u but expect %u\n", __func__, s->idx, s_port, + payload_type, ops->payload_type); + s->stat_pkts_wrong_pt_dropped++; return -EINVAL; } if (ops->ssrc) { uint32_t ssrc = ntohl(rtp->base.ssrc); if (ssrc != ops->ssrc) { - s->stat_pkts_wrong_hdr_dropped++; + dbg("%s(%d,%d), get ssrc %u but expect %u\n", __func__, s->idx, s_port, ssrc, + ops->ssrc); + s->stat_pkts_wrong_ssrc_dropped++; return -EINVAL; } } @@ -2394,13 +2441,13 @@ static int rv_handle_detect_pkt(struct st_rx_video_session_impl* s, struct rte_m if (payload_type != ops->payload_type) { dbg("%s, payload_type mismatch %d %d\n", __func__, payload_type, ops->payload_type); - s->stat_pkts_wrong_hdr_dropped++; + s->stat_pkts_wrong_pt_dropped++; return -EINVAL; } if (ops->ssrc) { uint32_t ssrc = ntohl(rtp->base.ssrc); if (ssrc != ops->ssrc) { - s->stat_pkts_wrong_hdr_dropped++; + s->stat_pkts_wrong_ssrc_dropped++; return -EINVAL; } } @@ -2915,7 +2962,6 @@ static int rv_attach(struct mtl_main_impl* impl, struct st_rx_video_sessions_mgr s->stat_pkts_no_slot = 0; s->stat_pkts_offset_dropped = 0; s->stat_pkts_redundant_dropped = 0; - s->stat_pkts_wrong_hdr_dropped = 0; s->stat_pkts_wrong_len_dropped = 0; s->stat_pkts_received = 0; s->stat_pkts_retransmit = 0; @@ -3179,10 +3225,20 @@ static void rv_stat(struct st_rx_video_sessions_mgr* mgr, s->stat_pkts_redundant_dropped); s->stat_pkts_redundant_dropped = 0; } - if (s->stat_pkts_wrong_hdr_dropped) { - notice("RX_VIDEO_SESSION(%d,%d): wrong hdr dropped pkts %d\n", m_idx, idx, - s->stat_pkts_wrong_hdr_dropped); - s->stat_pkts_wrong_hdr_dropped = 0; + if (s->stat_pkts_wrong_pt_dropped) { + notice("RX_VIDEO_SESSION(%d,%d): wrong hdr payload type dropped pkts %d\n", m_idx, + idx, s->stat_pkts_wrong_pt_dropped); + s->stat_pkts_wrong_pt_dropped = 0; + } + if (s->stat_pkts_wrong_ssrc_dropped) { + notice("RX_VIDEO_SESSION(%d,%d): wrong hdr ssrc dropped pkts %d\n", m_idx, idx, + s->stat_pkts_wrong_ssrc_dropped); + s->stat_pkts_wrong_ssrc_dropped = 0; + } + if (s->stat_pkts_wrong_interlace_dropped) { + notice("RX_VIDEO_SESSION(%d,%d): wrong hdr interlace dropped pkts %d\n", m_idx, idx, + s->stat_pkts_wrong_interlace_dropped); + s->stat_pkts_wrong_interlace_dropped = 0; } if (s->stat_pkts_wrong_len_dropped) { notice("RX_VIDEO_SESSION(%d,%d): wrong len dropped pkts %d\n", m_idx, idx, @@ -3270,6 +3326,17 @@ static void rv_stat(struct st_rx_video_sessions_mgr* mgr, s->stat_pkts_retransmit); s->stat_pkts_retransmit = 0; } + if (s->ops.interlaced) { + notice("RX_VIDEO_SESSION(%d,%d): interlace first field %u second field %u\n", m_idx, + idx, s->stat_interlace_first_field, s->stat_interlace_second_field); + s->stat_interlace_first_field = 0; + s->stat_interlace_second_field = 0; + } + if (s->stat_st22_boxes) { + notice("RX_VIDEO_SESSION(%d,%d): st22 video support boxes received %u \n", m_idx, idx, + s->stat_st22_boxes); + s->stat_st22_boxes = 0; + } if (s->ebu) rv_ebu_stat(s); } @@ -4194,6 +4261,7 @@ st22_rx_handle st22_rx_create(mtl_handle mt, struct st22_rx_ops* ops) { st20_ops.width = ops->width; st20_ops.height = ops->height; st20_ops.fps = ops->fps; + st20_ops.interlaced = ops->interlaced; st20_ops.fmt = ST20_FMT_YUV_422_10BIT; st20_ops.payload_type = ops->payload_type; st20_ops.ssrc = ops->ssrc; diff --git a/lib/src/st2110/st_tx_video_session.c b/lib/src/st2110/st_tx_video_session.c index 6c589446b..d24c60ebd 100644 --- a/lib/src/st2110/st_tx_video_session.c +++ b/lib/src/st2110/st_tx_video_session.c @@ -235,7 +235,7 @@ static int tv_alloc_frames(struct mtl_main_impl* impl, i); return -ENOMEM; } - if (st22_info) { /* copy boxes */ + if (st22_info && s->st22_box_hdr_length) { /* copy boxes */ mtl_memcpy(frame, &st22_info->st22_boxes, s->st22_box_hdr_length); } frame_info->iova = rte_mem_virt2iova(frame); @@ -604,8 +604,10 @@ static int tv_sync_pacing(struct mtl_main_impl* impl, struct st_tx_video_session if (interlaced) { if (second_field) { /* align to odd epoch */ if (!(epochs & 0x1)) epochs++; + s->stat_interlace_second_field++; } else { /* align to even epoch */ if (epochs & 0x1) epochs++; + s->stat_interlace_first_field++; } } @@ -687,6 +689,9 @@ static int tv_init_st22_next_meta(struct st_tx_video_session_impl* s, meta->height = ops->height; meta->fps = ops->fps; meta->codestream_size = s->st22_codestream_size; + if (ops->interlaced) { /* init second_field but user still can customize also */ + meta->second_field = s->second_field; + } /* point to next epoch */ meta->epoch = pacing->cur_epochs + 1; meta->tfmt = ST10_TIMESTAMP_FMT_TAI; @@ -1393,6 +1398,14 @@ static int tv_build_st22(struct st_tx_video_session_impl* s, struct rte_mbuf* pk rtp->f_counter_lo = f_counter; rtp->f_counter_hi = f_counter >> 2; + if (s->ops.interlaced) { + struct st_frame_trans* frame_info = &s->st20_frames[s->st20_frame_idx]; + if (frame_info->tx_st22_meta.second_field) + rtp->interlaced = 0x3; + else + rtp->interlaced = 0x2; + } + /* update mbuf */ mt_mbuf_init_ipv4(pkt); @@ -1459,6 +1472,14 @@ static int tv_build_st22_chain(struct st_tx_video_session_impl* s, struct rte_mb rtp->f_counter_lo = f_counter; rtp->f_counter_hi = f_counter >> 2; + if (s->ops.interlaced) { + struct st_frame_trans* frame_info = &s->st20_frames[s->st20_frame_idx]; + if (frame_info->tx_st22_meta.second_field) + rtp->interlaced = 0x3; + else + rtp->interlaced = 0x2; + } + /* update mbuf */ mt_mbuf_init_ipv4(pkt); pkt->data_len = sizeof(*hdr); @@ -2160,7 +2181,8 @@ static int tv_tasklet_st22(struct mtl_main_impl* impl, /* user timestamp control if any */ uint64_t required_tai = tv_pacing_required_tai(s, meta.tfmt, meta.timestamp); - tv_sync_pacing(impl, s, false, required_tai, false); + bool second_field = frame->tx_st22_meta.second_field; + tv_sync_pacing(impl, s, false, required_tai, second_field); if (ops->flags & ST20_TX_FLAG_USER_TIMESTAMP) { pacing->rtp_time_stamp = st10_get_media_clk(meta.tfmt, meta.timestamp, 90 * 1000); } @@ -2168,6 +2190,10 @@ static int tv_tasklet_st22(struct mtl_main_impl* impl, frame->tx_st22_meta.tfmt = ST10_TIMESTAMP_FMT_TAI; frame->tx_st22_meta.timestamp = pacing->cur_epoch_time; frame->tx_st22_meta.epoch = pacing->cur_epochs; + /* init to next field */ + if (ops->interlaced) { + s->second_field = second_field ? false : true; + } dbg("%s(%d), next_frame_idx %d(%d pkts) start\n", __func__, idx, next_frame_idx, s->st20_total_pkts); dbg("%s(%d), codestream_size %" PRId64 "(%d st22 pkts) time_stamp %u\n", __func__, @@ -2892,6 +2918,8 @@ static int tv_attach(struct mtl_main_impl* impl, struct st_tx_video_sessions_mgr s->st22_codestream_size = st22_frame_ops->framebuff_max_size; s->st20_frame_size = s->st22_codestream_size + s->st22_box_hdr_length; s->st20_fb_size = s->st20_frame_size; + info("%s(%d), st22 max codestream size %" PRId64 ", box len %u\n", __func__, idx, + s->st22_codestream_size, s->st22_box_hdr_length); } else { s->st20_frame_size = ops->width * height * s->st20_pg.size / s->st20_pg.coverage; s->st20_fb_size = s->st20_linesize * height; @@ -3194,6 +3222,12 @@ static void tv_stat(struct st_tx_video_sessions_mgr* mgr, s->stat_unrecoverable_error); /* not reset unrecoverable_error */ } + if (s->ops.interlaced) { + notice("TX_VIDEO_SESSION(%d,%d): interlace first field %u second field %u\n", m_idx, + idx, s->stat_interlace_first_field, s->stat_interlace_second_field); + s->stat_interlace_first_field = 0; + s->stat_interlace_second_field = 0; + } /* check frame busy stat */ if (s->st20_frames) { @@ -4252,6 +4286,7 @@ st22_tx_handle st22_tx_create(mtl_handle mt, struct st22_tx_ops* ops) { st20_ops.width = ops->width; st20_ops.height = ops->height; st20_ops.fps = ops->fps; + st20_ops.interlaced = ops->interlaced; st20_ops.fmt = ST20_FMT_YUV_422_10BIT; st20_ops.framebuff_cnt = ops->framebuff_cnt; st20_ops.payload_type = ops->payload_type; diff --git a/plugins/sample/st22_plugin_sample.c b/plugins/sample/st22_plugin_sample.c index fec46e5fc..ec9fcb106 100644 --- a/plugins/sample/st22_plugin_sample.c +++ b/plugins/sample/st22_plugin_sample.c @@ -20,6 +20,11 @@ static int encode_frame(struct st22_encoder_session* s, struct st22_encode_frame_meta* frame) { size_t codestream_size = s->req.max_codestream_size; + if (frame->src->interlaced) { + dbg("%s(%d), %s field\n", __func__, s->idx, + frame->src->second_field ? "second" : "first"); + } + /* call the real encode here, sample just copy and sleep */ memcpy(frame->dst->addr[0], frame->src->addr[0], codestream_size); st_usleep(10 * 1000); @@ -84,8 +89,9 @@ static st22_encode_priv encoder_create_session(void* priv, st22p_encode_session } ctx->encoder_sessions[i] = session; - info("%s(%d), input fmt: %s, output fmt: %s\n", __func__, i, - st_frame_fmt_name(req->input_fmt), st_frame_fmt_name(req->output_fmt)); + info("%s(%d), input fmt: %s, output fmt: %s, scan: %s\n", __func__, i, + st_frame_fmt_name(req->input_fmt), st_frame_fmt_name(req->output_fmt), + req->interlaced ? "interlaced" : "progressive"); info("%s(%d), max_codestream_size %" PRIu64 "\n", __func__, i, session->req.max_codestream_size); return session; @@ -130,6 +136,11 @@ static int decode_frame(struct st22_decoder_session* s, struct st22_decode_frame_meta* frame) { size_t codestream_size = frame->src->data_size; + if (frame->src->interlaced) { + dbg("%s(%d), %s field\n", __func__, s->idx, + frame->src->second_field ? "second" : "first"); + } + /* call the real decode here, sample just copy and sleep */ memcpy(frame->dst->addr[0], frame->src->addr[0], codestream_size); st_usleep(10 * 1000); @@ -190,8 +201,9 @@ static st22_decode_priv decoder_create_session(void* priv, st22p_decode_session } ctx->decoder_sessions[i] = session; - info("%s(%d), input fmt: %s, output fmt: %s\n", __func__, i, - st_frame_fmt_name(req->input_fmt), st_frame_fmt_name(req->output_fmt)); + info("%s(%d), input fmt: %s, output fmt: %s, scan: %s\n", __func__, i, + st_frame_fmt_name(req->input_fmt), st_frame_fmt_name(req->output_fmt), + req->interlaced ? "interlaced" : "progressive"); return session; } diff --git a/tests/script/loop_json/st22p_1v_1080i59.json b/tests/script/loop_json/st22p_1v_1080i59.json new file mode 100644 index 000000000..233f402ed --- /dev/null +++ b/tests/script/loop_json/st22p_1v_1080i59.json @@ -0,0 +1,68 @@ +{ + "interfaces": [ + { + "name": "0000:af:01.0", + "ip": "192.168.17.101" + }, + { + "name": "0000:af:01.1", + "ip": "192.168.17.102" + } + ], + "tx_sessions": [ + { + "dip": [ + "local:1" + ], + "interface": [ + 0 + ], + "st22p": [ + { + "replicas": 1, + "start_port": 50000, + "payload_type": 114, + "width": 1920, + "height": 1080, + "fps": "p59", + "interlaced": "true", + "codec": "JPEG-XS", + "device": "AUTO", + "quality": "speed", + "pack_type": "codestream", + "input_format": "YUV422RFC4175PG2BE10", + "codec_thread_count" : 2, + "st22p_url": "./test.yuv" + } + ] + } + ], + "rx_sessions": [ + { + "ip": [ + "local:0" + ], + "interface": [ + 1 + ], + "st22p": [ + { + "replicas": 1, + "start_port": 50000, + "payload_type": 114, + "width": 1920, + "height": 1080, + "fps": "p59", + "interlaced": "true", + "codec": "JPEG-XS", + "device": "AUTO", + "pack_type": "codestream", + "output_format": "YUV422RFC4175PG2BE10", + "codec_thread_count" : 2, + "display": false, + "measure_latency": true, + } + ] + } + ] +} diff --git a/tests/script/loop_json/st22p_interlaced_pcap.json b/tests/script/loop_json/st22p_interlaced_pcap.json new file mode 100644 index 000000000..5b8734e35 --- /dev/null +++ b/tests/script/loop_json/st22p_interlaced_pcap.json @@ -0,0 +1,63 @@ +{ + "interfaces": [ + { + "name": "0000:af:01.0", + "ip": "192.168.17.101" + }, + { + "name": "0000:af:01.1", + "ip": "192.168.17.102" + } + ], + "tx_sessions": [ + { + "dip": [ + "local:1" + ], + "interface": [ + 0 + ], + "video": [ + { + "replicas": 1, + "type": "rtp", + "pacing": "gap", + "packing": "BPM", + "start_port": 20000, + "payload_type": 101, + "tr_offset": "default", + "video_format": "i1080p59", + "pg_format": "YUV_422_10bit", + "video_url": "./test_st22_interlaced.pcap" + } + ] + } + ], + "rx_sessions": [ + { + "ip": [ + "local:0" + ], + "interface": [ + 1 + ], + "st22p": [ + { + "replicas": 1, + "start_port": 20000, + "payload_type": 101, + "width": 1920, + "height": 1080, + "fps": "p59", + "interlaced": "true", + "codec": "JPEG-XS", + "device": "AUTO", + "pack_type": "codestream", + "output_format": "YUV422RFC4175PG2BE10", + "codec_thread_count" : 2, + "display": false + } + ] + } + ] +} diff --git a/tests/script/loop_json/st22p_pcap.json b/tests/script/loop_json/st22p_pcap.json index 5046ce0b4..9227b574b 100644 --- a/tests/script/loop_json/st22p_pcap.json +++ b/tests/script/loop_json/st22p_pcap.json @@ -12,7 +12,7 @@ "tx_sessions": [ { "dip": [ - "192.168.17.102" + "local:1" ], "interface": [ 0 @@ -36,7 +36,7 @@ "rx_sessions": [ { "ip": [ - "192.168.17.101" + "local:0" ], "interface": [ 1 @@ -46,13 +46,14 @@ "replicas": 1, "start_port": 20000, "payload_type": 112, - "width": 3840, - "height": 2160, + "width": 1920, + "height": 1080, "fps": "p59", "codec": "JPEG-XS", "device": "AUTO", "pack_type": "codestream", - "output_format": "BGRA", + "output_format": "YUV422RFC4175PG2BE10", + "codec_thread_count" : 2, "display": false } ] diff --git a/tests/src/st22p_test.cpp b/tests/src/st22p_test.cpp index d72c0b6d6..0e57eaa35 100644 --- a/tests/src/st22p_test.cpp +++ b/tests/src/st22p_test.cpp @@ -717,6 +717,7 @@ struct st22p_rx_digest_test_para { bool rtcp; bool tx_ext; bool rx_ext; + bool interlace; uint32_t ssrc; }; @@ -735,6 +736,7 @@ static void test_st22p_init_rx_digest_para(struct st22p_rx_digest_test_para* par para->rtcp = false; para->tx_ext = false; para->rx_ext = false; + para->interlace = false; para->ssrc = 0; } @@ -828,6 +830,7 @@ static void st22p_rx_digest_test(enum st_fps fps[], int width[], int height[], ops_tx.width = width[i]; ops_tx.height = height[i]; ops_tx.fps = fps[i]; + ops_tx.interlaced = para->interlace; ops_tx.input_fmt = fmt[i]; ops_tx.pack_type = ST22_PACK_CODESTREAM; ops_tx.codec = codec[i]; @@ -852,13 +855,15 @@ static void st22p_rx_digest_test(enum st_fps fps[], int width[], int height[], } test_ctx_tx[i]->frame_size = - st_frame_size(ops_tx.input_fmt, ops_tx.width, ops_tx.height, false); + st_frame_size(ops_tx.input_fmt, ops_tx.width, ops_tx.height, ops_tx.interlaced); ops_tx.codestream_size = test_ctx_tx[i]->frame_size / compress_ratio[i]; tx_handle[i] = st22p_tx_create(st, &ops_tx); ASSERT_TRUE(tx_handle[i] != NULL); + EXPECT_EQ(test_ctx_tx[i]->frame_size, st22p_tx_frame_size(tx_handle[i])); + /* init ext frames, only for no convert */ if (para->tx_ext) { uint8_t planes = st_frame_fmt_planes(fmt[i]); @@ -1003,6 +1008,7 @@ static void st22p_rx_digest_test(enum st_fps fps[], int width[], int height[], ops_rx.width = width[i]; ops_rx.height = height[i]; ops_rx.fps = fps[i]; + ops_rx.interlaced = para->interlace; ops_rx.output_fmt = fmt[i]; ops_rx.pack_type = ST22_PACK_CODESTREAM; ops_rx.codec = codec[i]; @@ -1028,11 +1034,13 @@ static void st22p_rx_digest_test(enum st_fps fps[], int width[], int height[], } test_ctx_rx[i]->frame_size = - st_frame_size(ops_rx.output_fmt, ops_rx.width, ops_rx.height, false); + st_frame_size(ops_rx.output_fmt, ops_rx.width, ops_rx.height, ops_rx.interlaced); rx_handle[i] = st22p_rx_create(st, &ops_rx); ASSERT_TRUE(rx_handle[i] != NULL); + EXPECT_EQ(test_ctx_rx[i]->frame_size, st22p_rx_frame_size(rx_handle[i])); + test_ctx_rx[i]->handle = rx_handle[i]; rx_thread[i] = std::thread(test_st22p_rx_frame_thread, test_ctx_rx[i]); @@ -1140,6 +1148,22 @@ TEST(St22p, digest_st22_1080p_s1) { st22p_rx_digest_test(fps, width, height, fmt, codec, compress_ratio, ¶); } +TEST(St22p, digest_st22_1080i) { + enum st_fps fps[1] = {ST_FPS_P59_94}; + int width[1] = {1920}; + int height[1] = {1080}; + enum st_frame_fmt fmt[1] = {ST_FRAME_FMT_YUV422PLANAR10LE}; + enum st22_codec codec[1] = {ST22_CODEC_JPEGXS}; + int compress_ratio[1] = {10}; + + struct st22p_rx_digest_test_para para; + test_st22p_init_rx_digest_para(¶); + para.level = ST_TEST_LEVEL_MANDATORY; + para.interlace = true; + + st22p_rx_digest_test(fps, width, height, fmt, codec, compress_ratio, ¶); +} + TEST(St22p, digest_st22_4k_s1) { enum st_fps fps[1] = {ST_FPS_P59_94}; int width[1] = {1920 * 2};