From f070e63fda2f558dd24459be3891e1e69869b4e4 Mon Sep 17 00:00:00 2001 From: vanhofen Date: Wed, 25 Jan 2023 22:33:05 +0100 Subject: [PATCH] libeplayer: add missing files Origin commit data ------------------ Branch: master Commit: https://github.com/neutrino-images/ni-libstb-hal/commit/c1097d967f2a6c967e37f373645cb3ace644d8a6 Author: vanhofen Date: 2023-01-25 (Wed, 25 Jan 2023) Origin message was: ------------------ - libeplayer: add missing files ------------------ No further description and justification available within origin commit message! ------------------ This commit was generated by Migit --- libeplayer3/external/ffmpeg/src/xiph.c | 76 ++++++ libeplayer3/external/ffmpeg/xiph.h | 43 +++ libeplayer3/external/plugins/png.h | 8 + libeplayer3/external/plugins/src/png.c | 80 ++++++ libeplayer3/output/graphic_subtitle.c | 339 ++++++++++++++++++++++++ libeplayer3/output/writer/mipsel/bcma.c | 292 ++++++++++++++++++++ 6 files changed, 838 insertions(+) create mode 100644 libeplayer3/external/ffmpeg/src/xiph.c create mode 100644 libeplayer3/external/ffmpeg/xiph.h create mode 100644 libeplayer3/external/plugins/png.h create mode 100644 libeplayer3/external/plugins/src/png.c create mode 100644 libeplayer3/output/graphic_subtitle.c create mode 100644 libeplayer3/output/writer/mipsel/bcma.c diff --git a/libeplayer3/external/ffmpeg/src/xiph.c b/libeplayer3/external/ffmpeg/src/xiph.c new file mode 100644 index 0000000..0209329 --- /dev/null +++ b/libeplayer3/external/ffmpeg/src/xiph.c @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2007 The FFmpeg Project + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include "../xiph.h" + +int avpriv_split_xiph_headers(const uint8_t *extradata, int extradata_size, + int first_header_size, const uint8_t *header_start[3], + int header_len[3]) +{ + int i; + + if (extradata_size >= 6 && AV_RB16(extradata) == first_header_size) + { + int overall_len = 6; + for (i = 0; i < 3; i++) + { + header_len[i] = AV_RB16(extradata); + extradata += 2; + header_start[i] = extradata; + extradata += header_len[i]; + + if (overall_len > extradata_size - header_len[i]) + return -1; + + overall_len += header_len[i]; + } + } + else if (extradata_size >= 3 && extradata_size < INT_MAX - 0x1ff && extradata[0] == 2) + { + int overall_len = 3; + extradata++; + for (i = 0; i < 2; i++, extradata++) + { + header_len[i] = 0; + for (; overall_len < extradata_size && *extradata == 0xff; extradata++) + { + header_len[i] += 0xff; + overall_len += 0xff + 1; + } + + header_len[i] += *extradata; + overall_len += *extradata; + + if (overall_len > extradata_size) + return -1; + } + header_len[2] = extradata_size - overall_len; + header_start[0] = extradata; + header_start[1] = header_start[0] + header_len[0]; + header_start[2] = header_start[1] + header_len[1]; + } + else + { + return -1; + } + + return 0; +} \ No newline at end of file diff --git a/libeplayer3/external/ffmpeg/xiph.h b/libeplayer3/external/ffmpeg/xiph.h new file mode 100644 index 0000000..2ed3656 --- /dev/null +++ b/libeplayer3/external/ffmpeg/xiph.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2007 The FFmpeg Project + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_XIPH_H +#define AVCODEC_XIPH_H + +#include + +/** + * Split a single extradata buffer into the three headers that most + * Xiph codecs use. (e.g. Theora and Vorbis) + * Works both with Matroska's packing and lavc's packing. + * + * @param[in] extradata The single chunk that combines all three headers + * @param[in] extradata_size The size of the extradata buffer + * @param[in] first_header_size The size of the first header, used to + * differentiate between the Matroska packing and lavc packing. + * @param[out] header_start Pointers to the start of the three separate headers. + * @param[out] header_len The sizes of each of the three headers. + * @return On error a negative value is returned, on success zero. + */ +int avpriv_split_xiph_headers(const uint8_t *extradata, int extradata_size, + int first_header_size, const uint8_t *header_start[3], + int header_len[3]); + +#endif /* AVCODEC_XIPH_H */ \ No newline at end of file diff --git a/libeplayer3/external/plugins/png.h b/libeplayer3/external/plugins/png.h new file mode 100644 index 0000000..2a722af --- /dev/null +++ b/libeplayer3/external/plugins/png.h @@ -0,0 +1,8 @@ +#ifndef _exteplayer3_external_plugins_png_ +#define _exteplayer3_external_plugins_png_ + +int PNGPlugin_saveRGBAImage(const char *filename, const unsigned char *data, int width, int height); +int PNGPlugin_init(void); +int PNGPlugin_term(void); + +#endif // _exteplayer3_external_plugins_png_ diff --git a/libeplayer3/external/plugins/src/png.c b/libeplayer3/external/plugins/src/png.c new file mode 100644 index 0000000..4e726f8 --- /dev/null +++ b/libeplayer3/external/plugins/src/png.c @@ -0,0 +1,80 @@ +/* + * Subtitle output to one registered client. + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +/* ***************************** */ +/* Includes */ +/* ***************************** */ + +#include +#include +#include "plugins/png.h" +#include "debug.h" + +static void *handle; +int (*SaveRGBAImage_handle)(const char *filename, const unsigned char *data, int width, int height); + +int PNGPlugin_saveRGBAImage(const char *filename, const unsigned char *data, int width, int height) +{ + if (SaveRGBAImage_handle != NULL) + return SaveRGBAImage_handle(filename, data, width, height); + + return -1; +} + +int PNGPlugin_init(void) +{ + if (NULL != handle) + return 0; /* Already initialized */ + else + { + handle = dlopen("exteplayer3png.so", RTLD_LAZY); + if (handle) + { + char *error = NULL; + dlerror(); /* Clear any existing error */ + *(void **)(&SaveRGBAImage_handle) = dlsym(handle, "SaveRGBAImage"); + + if ((error = dlerror()) != NULL) + { + dlclose(handle); + plugin_err("%s\n", error); + return -2; + } + + return 0; + } + plugin_err("%s\n", dlerror()); + } + + return -1; +} + +int PNGPlugin_term(void) +{ + if (handle) + { + dlclose(handle); + handle = NULL; + SaveRGBAImage_handle = NULL; + return 0; + } + + return -1; +} diff --git a/libeplayer3/output/graphic_subtitle.c b/libeplayer3/output/graphic_subtitle.c new file mode 100644 index 0000000..ce50eb0 --- /dev/null +++ b/libeplayer3/output/graphic_subtitle.c @@ -0,0 +1,339 @@ +/* + * Subtitle output to one registered client. + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +/* ***************************** */ +/* Includes */ +/* ***************************** */ + +#include +#include +#include + +#include +#include +#include + +#include "common.h" +#include "debug.h" +#include "writer.h" +#include "plugins/png.h" + +/* ***************************** */ +/* Makros/Constants */ +/* ***************************** */ + +#define MAX_RECT_DESC 4 + +/* ***************************** */ +/* Types */ +/* ***************************** */ + +typedef struct +{ + AVCodecContext *p_context; + struct SwsContext *p_swctx; + const AVCodec *p_codec; + bool b_need_ephemer; /* Does the format need the ephemer flag (no end time set) */ +} decoder_sys_t; + +typedef struct +{ + char filename[50]; + int x; + int y; + int w; + int h; +} rec_desc_t; + +/* ***************************** */ +/* Variables */ +/* ***************************** */ + +static decoder_sys_t *g_sys; + +/* ***************************** */ +/* Prototypes */ +/* ***************************** */ + +/* ***************************** */ +/* MISC Functions */ +/* ***************************** */ + +#include +#include +#include +#include +#include +#include + +static bool IsRegular(const char *pPath) +{ + struct stat st = {0}; + + if (0 == lstat(pPath, &st) && S_ISREG(st.st_mode)) + { + return true; + } + return false; +} + +static void RemoveAllRegularFiles(const char *mainDir, const char *filePattern) +{ + if (!mainDir || !filePattern) + return; + + DIR *dirp = opendir(mainDir); + if (0 == dirp) + return; + + struct dirent *pDir = 0; + char *fullpath = malloc(PATH_MAX + 2); + + if (fullpath) + { + while (1) + { + pDir = readdir(dirp); + if (0 == pDir) + break; + + if (pDir->d_type != DT_REG && pDir->d_type != DT_UNKNOWN) + continue; + + snprintf(fullpath, PATH_MAX, "%s/%s", mainDir, pDir->d_name); + if (pDir->d_type == DT_UNKNOWN && !IsRegular(fullpath)) + continue; + + if (0 == fnmatch(filePattern, pDir->d_name, 0)) + remove(fullpath); + } + } + free(fullpath); + closedir(dirp); +} + +/* ***************************** */ +/* Functions */ +/* ***************************** */ + +static int32_t Reset() +{ + if (g_sys) + avcodec_flush_buffers(g_sys->p_context); + RemoveAllRegularFiles(GetGraphicSubPath(), "[0-9]*_[0-9]*_[0-9]*.png"); + return 0; +} + +static int32_t Open(SubtitleCodecId_t codecId, uint8_t *extradata, int extradata_size) +{ + enum AVCodecID avCodecId = AV_CODEC_ID_NONE; + const AVCodec *codec; + bool b_need_ephemer = false; + /* */ + switch (codecId) + { + case SUBTITLE_CODEC_ID_PGS: + avCodecId = AV_CODEC_ID_HDMV_PGS_SUBTITLE; + b_need_ephemer = true; + break; + case SUBTITLE_CODEC_ID_DVB: + avCodecId = AV_CODEC_ID_DVB_SUBTITLE; + b_need_ephemer = true; + break; + case SUBTITLE_CODEC_ID_XSUB: + avCodecId = AV_CODEC_ID_XSUB; + break; + default: + subtitle_err("unsupported subtitle codecId: %d\n", (int)codecId); + return -1; + } + + codec = avcodec_find_decoder(avCodecId); + AVCodecContext *context = avcodec_alloc_context3(codec); + Reset(); + + if (context == NULL) + return -1; + + g_sys = malloc(sizeof(*g_sys)); + + if (g_sys == NULL) + { + avcodec_free_context(&context); + return -1; + } + + g_sys->p_context = context; + g_sys->p_codec = codec; + /* this mean that new subtitles atom overwrite the previous one */ + g_sys->b_need_ephemer = b_need_ephemer; + g_sys->p_swctx = NULL; + /* */ + context->extradata = extradata; + context->extradata_size = extradata_size; + //av_codec_set_pkt_timebase(context, AV_TIME_BASE_Q); + context->pkt_timebase = AV_TIME_BASE_Q; + int ret = avcodec_open2(context, codec, NULL); + + if (ret < 0) + { + free(g_sys); + avcodec_free_context(&context); + return -1; + } + + /* Lazy PNG plugin init */ + ret = PNGPlugin_init(); + if (0 != ret) + { + /* Report plugin error */ + E2iSendMsg("{\"e_plugin\":[\"png\",\"init\",%d]}\n", ret); + } + return 0; +} + +static int32_t Close() +{ + if (g_sys) + { + AVCodecContext *ctx = g_sys->p_context; + if (ctx) + { + /* extradata is not allocated by us */ + ctx->extradata = NULL; + ctx->extradata_size = 0; + avcodec_free_context(&ctx); + } + sws_freeContext(g_sys->p_swctx); + free(g_sys); + g_sys = NULL; + } + Reset(); + return 0; +} + +static int32_t Write(WriterSubCallData_t *subPacket) +{ + if (!subPacket) + return -1; + + if (!g_sys) + if (Open(subPacket->codecId, subPacket->private_data, subPacket->private_size)) + return -1; + AVSubtitle subtitle; + memset(&subtitle, 0, sizeof(subtitle)); + AVPacket *pkt; + pkt = av_packet_alloc(); + pkt->data = subPacket->data; + pkt->size = subPacket->len; + pkt->pts = subPacket->pts; + int has_subtitle = 0; + //int used = avcodec_decode_subtitle2(g_sys->p_context, &subtitle, &has_subtitle, &pkt); + uint32_t width = g_sys->p_context->width > 0 ? g_sys->p_context->width : subPacket->width; + uint32_t height = g_sys->p_context->height > 0 ? g_sys->p_context->height : subPacket->height; + + if (has_subtitle && width > 0 && height > 0) + { + uint32_t i = 0; + uint32_t j = 0; + uint64_t startTimestamp = subPacket->pts / 90 + subtitle.start_display_time; + uint64_t endTimestamp = subPacket->pts / 90 + subtitle.end_display_time; + rec_desc_t desc_tab[MAX_RECT_DESC]; + for (; i < subtitle.num_rects && j < MAX_RECT_DESC; i++) + { + AVSubtitleRect *rec = subtitle.rects[i]; + switch (subtitle.format) + { + case 0: /* 0 = graphics */ + { + snprintf(desc_tab[j].filename, sizeof(desc_tab[j].filename), "%u_%"PRId64"_%u.png", subPacket->trackId, startTimestamp, i); + ssize_t bufsz = snprintf(NULL, 0, "%s/%s", GetGraphicSubPath(), desc_tab[j].filename); + char *filepath = malloc(bufsz + 1); + + if (!filepath) + { + subtitle_err("out of memory\n"); + break; + } + + snprintf(filepath, bufsz + 1, "%s/%s", GetGraphicSubPath(), desc_tab[j].filename); + desc_tab[j].x = av_rescale(rec->x, GetGraphicWindowWidth(), width); + desc_tab[j].y = av_rescale(rec->y, GetGraphicWindowHeight(), height); + desc_tab[j].w = av_rescale(rec->w, GetGraphicWindowWidth(), width); + desc_tab[j].h = av_rescale(rec->h, GetGraphicWindowHeight(), height); + subtitle_printf(50, "SUB_REC: src x[%d], y[%d], %dx%d\n", rec->x, rec->y, rec->w, rec->h); + subtitle_printf(50, "SUB_REC: dest x[%d], y[%d], %dx%d\n", desc_tab[j].x, desc_tab[j].y, desc_tab[j].w, desc_tab[j].h); + uint8_t *data[AV_NUM_DATA_POINTERS] = {NULL}; + int linesize[AV_NUM_DATA_POINTERS] = {0}; + data[0] = av_malloc(desc_tab[j].w * desc_tab[j].h * 4); + linesize[0] = desc_tab[j].w * 4; + + if (!data[0]) + { + subtitle_err("out of memory\n"); + free(filepath); + break; + } + + g_sys->p_swctx = sws_getCachedContext(g_sys->p_swctx, rec->w, rec->h, AV_PIX_FMT_PAL8, desc_tab[j].w, desc_tab[j].h, AV_PIX_FMT_RGBA, SWS_BICUBIC, NULL, NULL, NULL); // SWS_FAST_BILINEAR + sws_scale(g_sys->p_swctx, (const uint8_t *const *)rec->data, rec->linesize, 0, rec->h, data, linesize); + + if (0 == PNGPlugin_saveRGBAImage(filepath, &(data[0][0]), desc_tab[j].w, desc_tab[j].h)) + { + j += 1; + } + av_freep(&data[0]); + free(filepath); + break; + } + default: + subtitle_err("unsupported subtitle type\n"); + break; + } + } + char sep[2] = {'\0'}; + E2iStartMsg(); + E2iSendMsg("{\"s_a\":{\"id\":%d,\"s\":%"PRId64, subPacket->trackId, startTimestamp); + + if (g_sys->b_need_ephemer) + E2iSendMsg(",\"e\":null,\"r\":["); + else + E2iSendMsg(",\"e\":%"PRId64",\"r\":[", endTimestamp); + + for (i = 0; i < j; i++) + { + E2iSendMsg("%s{\"x\":%d,\"y\":%d,\"w\":%d,\"h\":%d,\"f\":\"%s\"}", sep, desc_tab[i].x, desc_tab[i].y, desc_tab[i].w, desc_tab[i].h, desc_tab[i].filename); + sep[0] = ','; + } + E2iSendMsg("]}}\n"); + E2iEndMsg(); + } + + avsubtitle_free(&subtitle); + return 0; +} + +SubWriter_t WriterSubPGS = +{ + NULL, + Close, + Reset, + Write +}; diff --git a/libeplayer3/output/writer/mipsel/bcma.c b/libeplayer3/output/writer/mipsel/bcma.c new file mode 100644 index 0000000..2abd8d5 --- /dev/null +++ b/libeplayer3/output/writer/mipsel/bcma.c @@ -0,0 +1,292 @@ +/* + * linuxdvb output/writer handling. + * + * konfetti 2010 based on linuxdvb.c code from libeplayer2 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +/* ***************************** */ +/* Includes */ +/* ***************************** */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "stm_ioctls.h" +#include "bcm_ioctls.h" + +#include "common.h" +#include "output.h" +#include "debug.h" +#include "misc.h" +#include "pes.h" +#include "writer.h" +#include "pcm.h" +#include "ffmpeg/xiph.h" + +/* ***************************** */ +/* Makros/Constants */ +/* ***************************** */ + +/* ***************************** */ +/* Types */ +/* ***************************** */ + +/* ***************************** */ +/* Variables */ +/* ***************************** */ + +/* ***************************** */ +/* Prototypes */ +/* ***************************** */ + +/* ***************************** */ +/* MISC Functions */ +/* ***************************** */ + +static int reset() +{ + return 0; +} + +static int writeData(WriterAVCallData_t *call) +{ + if (call == NULL || call->data == NULL || call->len <= 0 || call->fd < 0 || !call->private_data || call->private_size != sizeof(pcmPrivateData_t)) + { + bcma_err("Wrong input call: %p, data: %p, len: %d, fd: %d\n", call, call->data, call->len, call->fd); + return 0; + } + + bcma_printf(10, "AudioPts %lld\n", call->Pts); + uint8_t PesHeader[PES_MAX_HEADER_SIZE + 22]; + uint32_t i; + uint32_t private_size = 0; + const uint8_t *vorbis_header_start[3]; + int vorbis_header_len[3]; + uint8_t vorbis_header_len_raw[3][2]; + pcmPrivateData_t *pcmPrivateData = (pcmPrivateData_t *)call->private_data; + uint32_t headerSize = InsertPesHeader(PesHeader, call->len, MPEG_AUDIO_PES_START_CODE, call->Pts, 0); + + if (pcmPrivateData->codec_id == AV_CODEC_ID_VORBIS) + { + if (avpriv_split_xiph_headers(pcmPrivateData->private_data, pcmPrivateData->private_size, 30, vorbis_header_start, vorbis_header_len) < 0) + { + bcma_err("Wrong VORBIS codec data : %p, len: %d\n", pcmPrivateData->private_data, pcmPrivateData->private_size); + return -1; + } + + for (i = 0; i < 3; ++i) + { + vorbis_header_len_raw[i][0] = (vorbis_header_len[i] >> 8) & 0xff; + vorbis_header_len_raw[i][1] = vorbis_header_len[i] & 0xff; + private_size += 2 + vorbis_header_len[i]; + } + } + else + { + private_size = pcmPrivateData->private_size; + } + + if (STB_DREAMBOX == GetSTBType()) + { + PesHeader[headerSize++] = 'B'; + PesHeader[headerSize++] = 'C'; + PesHeader[headerSize++] = 'M'; + PesHeader[headerSize++] = 'A'; + } + + if (pcmPrivateData->codec_id != AV_CODEC_ID_VORBIS || pcmPrivateData->codec_id != AV_CODEC_ID_OPUS || STB_HISILICON != GetSTBType()) + { + uint32_t payloadSize = call->len; + PesHeader[headerSize++] = (payloadSize >> 24) & 0xFF; + PesHeader[headerSize++] = (payloadSize >> 16) & 0xFF; + PesHeader[headerSize++] = (payloadSize >> 8) & 0xFF; + PesHeader[headerSize++] = payloadSize & 0xFF; + int32_t channels = pcmPrivateData->channels; + uint32_t sample_rate = pcmPrivateData->sample_rate; + int32_t bits_per_sample = pcmPrivateData->bits_per_coded_sample; + uint32_t byte_rate = pcmPrivateData->bit_rate / 8; + uint32_t block_align = pcmPrivateData->block_align; + int32_t format_tag = 0; + + switch (pcmPrivateData->codec_id) + { + case AV_CODEC_ID_WMAV1: + format_tag = 0x160; + break; + case AV_CODEC_ID_WMAV2: + format_tag = 0x161; + break; + case AV_CODEC_ID_WMAPRO: + format_tag = 0x162; + break; + case AV_CODEC_ID_WMALOSSLESS: + format_tag = 0x163; + break; + case AV_CODEC_ID_VORBIS: + bits_per_sample = 8; + byte_rate = 32000; + block_align = 1; + break; + default: + format_tag = 0xFFFF; + break; + } + /* format tag */ + PesHeader[headerSize++] = format_tag & 0xff; + PesHeader[headerSize++] = (format_tag >> 8) & 0xff; + /* channels */ + PesHeader[headerSize++] = channels & 0xff; + PesHeader[headerSize++] = (channels >> 8) & 0xff; + /* sample rate */ + PesHeader[headerSize++] = sample_rate & 0xff; + PesHeader[headerSize++] = (sample_rate >> 8) & 0xff; + PesHeader[headerSize++] = (sample_rate >> 16) & 0xff; + PesHeader[headerSize++] = (sample_rate >> 24) & 0xff; + /* byte rate */ + PesHeader[headerSize++] = byte_rate & 0xff; + PesHeader[headerSize++] = (byte_rate >> 8) & 0xff; + PesHeader[headerSize++] = (byte_rate >> 16) & 0xff; + PesHeader[headerSize++] = (byte_rate >> 24) & 0xff; + /* block align */ + PesHeader[headerSize++] = block_align & 0xff; + PesHeader[headerSize++] = (block_align >> 8) & 0xff; + /* bits per sample */ + PesHeader[headerSize++] = bits_per_sample & 0xff; + PesHeader[headerSize++] = (bits_per_sample >> 8) & 0xff; + /* Codec Specific Data Size */ + PesHeader[headerSize++] = private_size & 0xff; + PesHeader[headerSize++] = (private_size >> 8) & 0xff; + } + + PesHeader[6] |= 1; + UpdatePesHeaderPayloadSize(PesHeader, headerSize - 6 + private_size + call->len); + struct iovec iov[5]; + i = 0; + iov[i].iov_base = PesHeader; + iov[i++].iov_len = headerSize; + + if (private_size > 0) + { + if (pcmPrivateData->codec_id == AV_CODEC_ID_VORBIS) + { + for (i = 0; i < 3; ++i) + { + iov[i].iov_base = vorbis_header_len_raw[i]; + iov[i++].iov_len = 2; + iov[i].iov_base = vorbis_header_start; + iov[i++].iov_len = vorbis_header_len[i]; + } + } + else + { + iov[i].iov_base = pcmPrivateData->private_data; + iov[i++].iov_len = private_size; + } + } + iov[i].iov_base = call->data; + iov[i++].iov_len = call->len; + + return call->WriteV(call->fd, iov, i); +} + +/* ***************************** */ +/* Writer Definition */ +/* ***************************** */ + +static WriterCaps_t capsVORBIS = +{ + "vorbis", + eAudio, + "A_VORBIS", + -1, + AUDIOTYPE_VORBIS, + -1 +}; + +struct Writer_s WriterAudioVORBIS = +{ + &reset, + &writeData, + &capsVORBIS +}; + +static WriterCaps_t capsOPUS = +{ + "opus", + eAudio, + "A_OPUS", + -1, + AUDIOTYPE_OPUS, + -1 +}; + +struct Writer_s WriterAudioOPUS = +{ + &reset, + &writeData, + &capsOPUS +}; + +static WriterCaps_t capsWMAPRO = +{ + "wma/pro", + eAudio, + "A_WMA/PRO", + -1, + AUDIOTYPE_WMA_PRO, + -1 +}; + +struct Writer_s WriterAudioWMAPRO = +{ + &reset, + &writeData, + &capsWMAPRO +}; + +static WriterCaps_t capsWMA = +{ + "wma", + eAudio, + "A_WMA", + -1, + AUDIOTYPE_WMA, + -1 +}; + +struct Writer_s WriterAudioWMA = +{ + &reset, + &writeData, + &capsWMA +};