Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

python/st20p: add interlaced support #669

Merged
merged 3 commits into from
Dec 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
99 changes: 96 additions & 3 deletions app/tools/convert_app.c
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,90 @@ static int convert(struct conv_app_context* ctx) {
return ret;
}

static int frame2field(struct conv_app_context* ctx) {
enum cvt_frame_fmt fmt = ctx->fmt_in;
uint32_t w = ctx->w;
uint32_t h = ctx->h;
size_t frame_size = st_frame_size(fmt_cvt2frame(fmt), w, h, false);
size_t line_size = frame_size / h;
FILE *fp_in = NULL, *fp_out = NULL;
void* buf_in = NULL;
int ret = -EIO;

if (!frame_size) return -EIO;

fp_in = st_fopen(ctx->file_in, "rb");
if (!fp_in) {
err("%s, open %s fail\n", __func__, ctx->file_in);
ret = -EIO;
goto out;
}
fp_out = st_fopen(ctx->file_out, "wb");
if (!fp_out) {
err("%s, open %s fail\n", __func__, ctx->file_out);
ret = -EIO;
goto out;
}

buf_in = conv_app_zmalloc(frame_size);
if (!buf_in) {
ret = -EIO;
goto out;
}

// get the frame num
fseek(fp_in, 0, SEEK_END);
long size = ftell(fp_in);
int frame_num = size / frame_size;
if (frame_num < 0) {
err("%s, err size %ld\n", __func__, size);
ret = -EIO;
goto out;
}
info("%s, file size:%ld, %d frames(%ux%u), in %s(%d) out %s\n", __func__, size,
frame_num, w, h, ctx->file_in, fmt, ctx->file_out);

fseek(fp_in, 0, SEEK_SET);
for (int i = 0; i < frame_num; i++) {
int ret = fread(buf_in, 1, frame_size, fp_in);
if (ret < frame_size) {
err("%s, fread fail %d\n", __func__, ret);
ret = -EIO;
goto out;
}

void* frame = buf_in;
/* write the first field */
for (uint32_t line = 0; line < h; line += 2) {
fwrite(frame, 1, line_size, fp_out);
frame += line_size * 2;
}
frame = buf_in + line_size;
/* write the second field */
for (uint32_t line = 0; line < h; line += 2) {
fwrite(frame, 1, line_size, fp_out);
frame += line_size * 2;
}
}
ret = 0;

out:
if (fp_in) {
fclose(fp_in);
fp_in = NULL;
}
if (fp_out) {
fclose(fp_out);
fp_out = NULL;
}
if (buf_in) {
free(buf_in);
buf_in = NULL;
}

return ret;
}

int main(int argc, char** argv) {
int ret = -EIO;
struct conv_app_context* ctx;
Expand All @@ -337,8 +421,8 @@ int main(int argc, char** argv) {
return -EIO;
}

if ((ctx->fmt_in == CVT_FRAME_FMT_MAX) || (ctx->fmt_out == CVT_FRAME_FMT_MAX)) {
err("%s, invalid fmt in %d out %d\n", __func__, ctx->fmt_in, ctx->fmt_out);
if (ctx->fmt_in == CVT_FRAME_FMT_MAX) {
err("%s, invalid fmt in %d\n", __func__, ctx->fmt_in);
conv_app_free(ctx);
return -EIO;
}
Expand All @@ -354,7 +438,16 @@ int main(int argc, char** argv) {
return -EIO;
}

convert(ctx);
if (ctx->frame2field) {
frame2field(ctx);
} else {
if (ctx->fmt_out == CVT_FRAME_FMT_MAX) {
err("%s, invalid fmt out %d\n", __func__, ctx->fmt_out);
conv_app_free(ctx);
return -EIO;
}
convert(ctx);
}

/* free */
conv_app_free(ctx);
Expand Down
8 changes: 7 additions & 1 deletion app/tools/convert_app_args.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
#include <getopt.h>

#include "convert_app_base.h"
//#define DEBUG
// #define DEBUG
#include "log.h"

enum conv_args_cmd {
Expand All @@ -17,6 +17,7 @@ enum conv_args_cmd {
CONV_ARG_H,
CONV_ARG_FILE_IN,
CONV_ARG_FILE_OUT,
CONV_ARG_FRAME2FIELD,
CONV_ARG_HELP,
};

Expand All @@ -28,6 +29,7 @@ static struct option conv_app_args_options[] = {
{"i", required_argument, 0, CONV_ARG_FILE_IN},
{"o", required_argument, 0, CONV_ARG_FILE_OUT},
{"help", no_argument, 0, CONV_ARG_HELP},
{"frame2field", no_argument, 0, CONV_ARG_FRAME2FIELD},
{0, 0, 0, 0}};

static void conv_app_print_app() {
Expand All @@ -39,6 +41,7 @@ static void conv_app_print_app() {
printf(" --height : source height\n");
printf(" --in_pix_fmt : yuv422p10le, v210, yuv422rfc4175be10\n");
printf(" --out_pix_fmt : yuv422p10le, v210, yuv422rfc4175be10\n");
printf(" --frame2field : convert frame to field\n");
printf(" --i : input file\n");
printf(" --o : output file\n");
printf("\n");
Expand Down Expand Up @@ -120,6 +123,9 @@ int conv_app_parse_args(struct conv_app_context* ctx, int argc, char** argv) {
case CONV_ARG_FILE_OUT:
snprintf(ctx->file_out, sizeof(ctx->file_out), "%s", optarg);
break;
case CONV_ARG_FRAME2FIELD:
ctx->frame2field = true;
break;
case CONV_ARG_HELP:
conv_app_print_app();
ret = -EIO;
Expand Down
2 changes: 2 additions & 0 deletions app/tools/convert_app_base.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#endif
#include <errno.h>
#include <signal.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
Expand Down Expand Up @@ -60,6 +61,7 @@ struct conv_app_context {
enum cvt_frame_fmt fmt_out;
char file_in[MAX_FILE_NAME_LEN];
char file_out[MAX_FILE_NAME_LEN];
bool frame2field;
};

static inline void* conv_app_zmalloc(size_t sz) {
Expand Down
16 changes: 16 additions & 0 deletions doc/run.md
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,22 @@ ffmpeg -s 1920x1080 -pix_fmt yuv420p10le -i yuv420p10le_1080p.yuv -pix_fmt yuv44
./build/app/ConvApp -width 1920 -height 1080 -in_pix_fmt yuv444rfc4175be12 -i yuv444rfc4175be12_1080p.yuv -out_pix_fmt yuv444p12le -o out_yuv444p12le_1080p.yuv
```

#### 5.1.8 Interlaced support

ConvApp offers a `frame2field` option to convert a progressive YUV file into an interlaced file. The interlaced YUV file stores the first field followed by the second field, repeating this sequence.

For yuv422p10le:

```bash
./build/app/ConvApp --in_pix_fmt yuv422p10le --width 1920 --height 1080 --i yuv422p10le_1080p.yuv --o yuv422p10le_1080i.yuv --frame2field
```

For yuv422rfc4175be10:

```bash
./build/app/ConvApp --in_pix_fmt yuv422rfc4175be10 --width 1920 --height 1080 --i yuv422rfc4175be10_1080p.yuv --o yuv422rfc4175be10_1080i.yuv --frame2field
```

### 5.2 Run RxTxApp with json config

Before running samples the JSON configuration files must be modified. The "name" tag in "interfaces" must be updated to VF BDF, e.g 0000:af:01.0. No other changes are required to run samples.
Expand Down
7 changes: 7 additions & 0 deletions include/st_pipeline_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -1975,6 +1975,13 @@ struct st_frame* st_frame_create(mtl_handle mt, enum st_frame_fmt fmt, uint32_t
/** free the frame created by st_frame_create */
int st_frame_free(struct st_frame* frame);

/** merge two fields to one full frame */
int st_field_merge(const struct st_frame* first, const struct st_frame* second,
struct st_frame* frame);
/** split one full frame to two fields */
int st_field_split(const struct st_frame* frame, struct st_frame* first,
struct st_frame* second);

#if defined(__cplusplus)
}
#endif
Expand Down
89 changes: 89 additions & 0 deletions lib/src/st2110/st_convert.c
Original file line number Diff line number Diff line change
Expand Up @@ -595,6 +595,95 @@ int st_frame_convert(struct st_frame* src, struct st_frame* dst) {
return converter.convert_func(src, dst);
}

static int field_frame_check(const struct st_frame* field, const struct st_frame* frame) {
if (!field->interlaced) {
err("%s, field is not field\n", __func__);
return -EINVAL;
}
if (field->width != frame->width || field->height != frame->height) {
err("%s, width/height mismatch, field: %u x %u, frame: %u x %u\n", __func__,
field->width, field->height, frame->width, frame->height);
return -EINVAL;
}
if (field->fmt != frame->fmt) {
err("%s, fmt mismatch, field: %d, frame: %d\n", __func__, field->fmt, frame->fmt);
return -EINVAL;
}
return 0;
}

static int fields_frame_match(const struct st_frame* first, const struct st_frame* second,
const struct st_frame* frame) {
int ret = field_frame_check(first, frame);
if (ret < 0) {
err("%s, first field check fail %d\n", __func__, ret);
return -EINVAL;
}
if (first->second_field) {
err("%s, first is second field\n", __func__);
return -EINVAL;
}
ret = field_frame_check(second, frame);
if (ret < 0) {
err("%s, second field check fail %d\n", __func__, ret);
return -EINVAL;
}
if (!second->second_field) {
err("%s, second is first field\n", __func__);
return -EINVAL;
}
return 0;
}

int st_field_merge(const struct st_frame* first, const struct st_frame* second,
struct st_frame* frame) {
int ret = fields_frame_match(first, second, frame);
if (ret < 0) return ret;

uint8_t planes = st_frame_fmt_planes(frame->fmt);
for (uint32_t line = 0; line < frame->height; line += 2) {
for (uint8_t plane = 0; plane < planes; plane++) {
size_t linesize = st_frame_least_linesize(frame->fmt, frame->width, plane);
uint32_t field_line = line / 2;
/* first line */
void* f_addr = frame->addr[plane] + frame->linesize[plane] * line;
void* src = first->addr[plane] + first->linesize[plane] * field_line;
mtl_memcpy(f_addr, src, linesize);
/* second line */
f_addr = frame->addr[plane] + frame->linesize[plane] * (line + 1);
src = second->addr[plane] + second->linesize[plane] * field_line;
mtl_memcpy(f_addr, src, linesize);
}
}

return 0;
}

/** split one full frame to two fields */
int st_field_split(const struct st_frame* frame, struct st_frame* first,
struct st_frame* second) {
int ret = fields_frame_match(first, second, frame);
if (ret < 0) return ret;

uint8_t planes = st_frame_fmt_planes(frame->fmt);
for (uint32_t line = 0; line < frame->height; line += 2) {
for (uint8_t plane = 0; plane < planes; plane++) {
size_t linesize = st_frame_least_linesize(frame->fmt, frame->width, plane);
uint32_t field_line = line / 2;
/* first line */
void* f_addr = frame->addr[plane] + frame->linesize[plane] * line;
void* src = first->addr[plane] + first->linesize[plane] * field_line;
mtl_memcpy(src, f_addr, linesize);
/* second line */
f_addr = frame->addr[plane] + frame->linesize[plane] * (line + 1);
src = second->addr[plane] + second->linesize[plane] * field_line;
mtl_memcpy(src, f_addr, linesize);
}
}

return 0;
}

int st_frame_get_converter(enum st_frame_fmt src_fmt, enum st_frame_fmt dst_fmt,
struct st_frame_converter* converter) {
for (int i = 0; i < MTL_ARRAY_SIZE(converters); i++) {
Expand Down
12 changes: 10 additions & 2 deletions lib/src/st2110/st_rx_video_session.c
Original file line number Diff line number Diff line change
Expand Up @@ -1361,6 +1361,8 @@ static int rv_handle_frame_pkt(struct st_rx_video_session_impl* s, struct rte_mb
rte_pktmbuf_mtod_offset(mbuf, struct st20_rfc4175_rtp_hdr*, hdr_offset);
void* payload = &rtp[1];
uint16_t line1_number = ntohs(rtp->row_number); /* 0 to 1079 for 1080p */
bool second_field = (line1_number & ST20_SECOND_FIELD) ? true : false;
if (second_field) line1_number &= ~ST20_SECOND_FIELD;
uint16_t line1_offset = ntohs(rtp->row_offset); /* [0, 480, 960, 1440] for 1080p */
struct st20_rfc4175_extra_rtp_hdr* extra_rtp = NULL;
if (line1_offset & ST20_SRD_OFFSET_CONTINUATION) {
Expand Down Expand Up @@ -1397,6 +1399,13 @@ static int rv_handle_frame_pkt(struct st_rx_video_session_impl* s, struct rte_mb
return -EINVAL;
}
}
/* check interlace */
if (!s->ops.interlaced) {
if (second_field) {
s->stat_pkts_wrong_interlace_dropped++;
return -EINVAL;
}
}
if (mbuf_next && mbuf_next->data_len) {
/* for some reason mbuf splits into 2 segments (1024 bytes + left bytes) */
/* todo: payload needs to be copied from 2 places */
Expand Down Expand Up @@ -1434,8 +1443,7 @@ static int rv_handle_frame_pkt(struct st_rx_video_session_impl* s, struct rte_mb
}

uint8_t* bitmap = slot->frame_bitmap;
slot->second_field = (line1_number & ST20_SECOND_FIELD) ? true : false;
line1_number &= ~ST20_SECOND_FIELD;
slot->second_field = second_field;

/* calculate offset */
uint32_t offset;
Expand Down
Loading