/* module: av_common description: author: Bruce.Lu update: 2019/08/23 */ #ifndef __EV_AV_COMMON_H__ #define __EV_AV_COMMON_H__ extern "C" { #include #include } #include #include #include #include using json = nlohmann::json; #undef av_err2str #define av_err2str(errnum) av_make_error_string((char *)__builtin_alloca(AV_ERROR_MAX_STRING_SIZE), AV_ERROR_MAX_STRING_SIZE, errnum) #define PS_MARK_E "DEADBEEF" #define PS_MARK_S "BEEFDEAD" #define EV_LOG_PACKET_CNT (18*60*5) void avlogThrow(void *avcl, int lvl, const char *fmt, ...) { (void)avcl; (void)lvl; va_list args; va_start(args, fmt); av_log(NULL, AV_LOG_FATAL, fmt, args); va_end(args); throw fmt; } // AVPacketSerializer namespace AVPacketSerializer { int encode(AVPacket &pkt, char **bytes) { int cnt = 0; //data int wholeSize = strlen(PS_MARK_S) + sizeof(pkt.size) + pkt.size; //side data wholeSize += sizeof(pkt.side_data_elems); if (pkt.side_data_elems != 0) { for (int i = 0; i < pkt.side_data_elems; i++) { wholeSize += pkt.side_data[i].size + sizeof(AVPacketSideData); } } // 4 + 8: wholeSize + DEADBEAF wholeSize += sizeof(pkt.pts) * 4 + sizeof(pkt.flags) + sizeof(pkt.stream_index) + sizeof(wholeSize) + strlen(PS_MARK_E); *bytes = (char *)malloc(wholeSize); memcpy((*bytes) + cnt, PS_MARK_S, strlen(PS_MARK_S)); cnt += strlen(PS_MARK_S); // data memcpy((*bytes) + cnt, &(pkt.size), sizeof(pkt.size)); cnt += sizeof(pkt.size); memcpy((*bytes) + cnt, pkt.data, pkt.size); cnt += pkt.size; //side data memcpy((*bytes) + cnt, &(pkt.side_data_elems), sizeof(pkt.side_data_elems)); cnt += sizeof(pkt.side_data_elems); if (pkt.side_data_elems != 0) { for (int i = 0; i < pkt.side_data_elems; i++) { memcpy((*bytes) + cnt, &(pkt.side_data[i].size), sizeof(pkt.side_data[i].size)); cnt += sizeof(pkt.side_data[i].size); memcpy((*bytes) + cnt, pkt.side_data[i].data, pkt.side_data[i].size); cnt += pkt.side_data[i].size; memcpy((*bytes) + cnt, &(pkt.side_data[i].type), sizeof(pkt.side_data[i].type)); cnt += sizeof(pkt.side_data[i].type); } } // other properties memcpy((*bytes) + cnt, &(pkt.pts), sizeof(pkt.pts)); cnt += sizeof(pkt.pts); memcpy((*bytes) + cnt, &(pkt.dts), sizeof(pkt.dts)); cnt += 8; memcpy((*bytes) + cnt, &(pkt.pos), sizeof(pkt.pos)); cnt += sizeof(pkt.pos); memcpy((*bytes) + cnt, &(pkt.duration), sizeof(pkt.duration)); cnt += sizeof(pkt.duration); // deprecated //memcpy((*bytes )+cnt, &(pkt.convergence_duration), sizeof(pkt.convergence_duration)); //cnt+=sizeof(pkt.convergence_duration); memcpy((*bytes) + cnt, &(pkt.flags), sizeof(pkt.flags)); cnt += sizeof(pkt.flags); memcpy((*bytes) + cnt, &(pkt.stream_index), sizeof(pkt.stream_index)); cnt += sizeof(pkt.stream_index); memcpy((*bytes) + cnt, &wholeSize, sizeof(wholeSize)); cnt += sizeof(wholeSize); memcpy((*bytes) + cnt, PS_MARK_E, strlen(PS_MARK_E)); cnt += strlen(PS_MARK_E); assert(cnt == wholeSize); av_log(NULL, AV_LOG_DEBUG, "pkt origin size %d, serialized size: %d, elems: %d", pkt.size, wholeSize, pkt.side_data_elems); return wholeSize; } int decode(char *bytes, int len, AVPacket *pkt) { // allocate packet mem on heap //AVPacket *pkt = (AVPacket*)malloc(sizeof(AVPacket)); int ret = 0; int got = 0; if (memcmp(PS_MARK_E, bytes + len - strlen(PS_MARK_E), strlen(PS_MARK_E)) != 0 || memcmp(PS_MARK_S, bytes, strlen(PS_MARK_S))) { spdlog::error("invalid packet. len {}", len); return -1; } //skip mark_s got += strlen(PS_MARK_S); memcpy(&(pkt->size), bytes + got, sizeof(pkt->size)); got += sizeof(pkt->size); av_new_packet(pkt, pkt->size); memcpy(pkt->data, bytes + got, pkt->size); got += pkt->size; memcpy(&pkt->side_data_elems, bytes + got, sizeof(pkt->side_data_elems)); got += sizeof(pkt->side_data_elems); for (int i = 0; i < pkt->side_data_elems; i++) { memcpy(&(pkt->side_data[i].size), bytes + got, sizeof(pkt->side_data[i].size)); got += sizeof(pkt->side_data[i].size); memcpy(pkt->side_data[i].data, bytes + got, pkt->side_data[i].size); got += pkt->side_data[i].size; memcpy(&(pkt->side_data[i].type), bytes + got, sizeof(pkt->side_data[i].type)); got += sizeof(pkt->side_data[i].type); } // props memcpy(&(pkt->pts), bytes + got, sizeof(pkt->pts)); got += sizeof(pkt->pts); memcpy(&(pkt->dts), bytes + got, sizeof(pkt->dts)); got += sizeof(pkt->dts); memcpy(&(pkt->pos), bytes + got, sizeof(pkt->pos)); got += sizeof(pkt->pos); memcpy(&(pkt->duration), bytes + got, sizeof(pkt->duration)); got += sizeof(pkt->duration); // deprecated //memcpy(&(pkt->convergence_duration), bytes + got, sizeof(pkt->convergence_duration)); //got += sizeof(pkt->convergence_duration); memcpy(&(pkt->flags), bytes + got, sizeof(pkt->flags)); got += sizeof(pkt->flags); memcpy(&(pkt->stream_index), bytes + got, sizeof(pkt->stream_index)); got += sizeof(pkt->stream_index); int wholeSize = 0; memcpy(&wholeSize, bytes + got, sizeof(wholeSize)); got += sizeof(wholeSize); got += 8; //spdlog::debug("wholeSize: {:d}, {:d}", wholeSize, got); return ret; } } // namespace AVPacketSerializer void mqPacketFree(void *data, void *hint) { free(data); } // AVFormatCtxSerializer namespace AVFormatCtxSerializer { /** * memory layerout * PS_MARK_S | NUM_STREAMS | AVSTREAM+AVCODEPAR | WHOLESIZE | PS_MARK_E * */ int encode(AVFormatContext *ctx, char **bytes) { int ret = 0; int wholeSize = 0; int got = 0; // calc total size wholeSize += strlen(PS_MARK_S); // num streams wholeSize += sizeof(ctx->nb_streams); spdlog::debug("encode num of streams: {:d}", ctx->nb_streams); for (int i = 0; i < ctx->nb_streams; i++) { wholeSize += sizeof(AVStream); wholeSize += sizeof(AVCodecParameters); //extradata wholeSize += sizeof(ctx->streams[i]->codecpar->extradata_size); if(ctx->streams[i]->codecpar->extradata_size!=0){ wholeSize += ctx->streams[i]->codecpar->extradata_size; } } wholeSize += sizeof(wholeSize); wholeSize += strlen(PS_MARK_E); // alloc memory *bytes = (char *)malloc(wholeSize); // populate memcpy((*bytes) + got, PS_MARK_S, strlen(PS_MARK_S)); got += strlen(PS_MARK_S); memcpy((*bytes) + got, (void *)&(ctx->nb_streams), sizeof(ctx->nb_streams)); got += sizeof(ctx->nb_streams); for (int i = 0; i < ctx->nb_streams; i++) { // memcpy((*bytes) + got, ctx->streams[i], sizeof(AVStream)); got += sizeof(AVStream); // memcpy((*bytes) + got, ctx->streams[i]->codecpar, sizeof(AVCodecParameters)); got += sizeof(AVCodecParameters); //extra memcpy((*bytes) + got, &(ctx->streams[i]->codecpar->extradata_size), sizeof(int)); got += sizeof(int); memcpy((*bytes) + got,ctx->streams[i]->codecpar->extradata, ctx->streams[i]->codecpar->extradata_size); got += ctx->streams[i]->codecpar->extradata_size; } memcpy((*bytes) + got, &wholeSize, sizeof(wholeSize)); got += sizeof(wholeSize); memcpy((*bytes) + got, PS_MARK_E, strlen(PS_MARK_E)); got += strlen(PS_MARK_E); if(wholeSize != got){ spdlog::error("encode wholesize: {}, should be {}", got, wholeSize); } assert(wholeSize == got); return wholeSize; } int decode(char *bytes, int len, AVFormatContext *pCtx) { int ret = 0; int got = 0; memcpy(&ret, bytes +len -strlen(PS_MARK_E) - sizeof(ret), sizeof(ret)); if ((memcmp(PS_MARK_S, bytes + got, strlen(PS_MARK_S)) != 0 && memcmp(PS_MARK_E, bytes + len - strlen(PS_MARK_E), strlen(PS_MARK_E)) != 0)||ret != len) { spdlog::error("invalid avformatctx: {} {}", ret, len); return -1; } spdlog::debug("decode len: {}", ret); got += strlen(PS_MARK_S); memcpy(&ret, bytes + got, sizeof(ret)); got += sizeof(ret); pCtx->streams = (AVStream **)malloc(sizeof(AVStream *) * ret); pCtx->nb_streams = ret; for (int i = 0; i < ret; i++) { pCtx->streams[i] = (AVStream *)malloc(sizeof(AVStream)); memcpy(pCtx->streams[i], bytes + got, sizeof(AVStream)); got += sizeof(AVStream); pCtx->streams[i]->codecpar = (AVCodecParameters *)malloc(sizeof(AVCodecParameters)); memcpy(pCtx->streams[i]->codecpar, bytes + got, sizeof(AVCodecParameters)); got += sizeof(AVCodecParameters); // extra memcpy(&ret, bytes + got, sizeof(int)); got += sizeof(int); if(ret != 0) { pCtx->streams[i]->codecpar->extradata_size = ret; pCtx->streams[i]->codecpar->extradata = (uint8_t *)malloc(ret); memcpy(pCtx->streams[i]->codecpar->extradata, bytes + got, ret); got += ret; } } memcpy(&ret, bytes + got, sizeof(ret)); got += sizeof(ret); got += strlen(PS_MARK_E); if(len != ret) { spdlog::error("avformatctx decode: {:d} {:d} {:d}", ret, len, got); } assert(ret == len); return ret; } void freeCtx(AVFormatContext *pCtx) { for (int i = 0; i < pCtx->nb_streams; i++) { free(pCtx->streams[i]->codecpar); if(pCtx->streams[i]->codecpar->extradata_size != 0) { free(pCtx->streams[i]->codecpar->extradata); } free(pCtx->streams[i]); } free(pCtx->streams); } } // namespace AVFormatCtxSerializer #endif