|  | @@ -1,5 +1,5 @@ | 
														
													
														
															
																|  |  | /* |  |  | /* | 
														
													
														
															
																|  |  | * Argonaut Games ASF demuxer |  |  |  | 
														
													
														
															
																|  |  |  |  |  | * Argonaut Games ASF (de)muxer | 
														
													
														
															
																|  |  | * |  |  | * | 
														
													
														
															
																|  |  | * Copyright (C) 2020 Zane van Iperen (zane@zanevaniperen.com) |  |  | * Copyright (C) 2020 Zane van Iperen (zane@zanevaniperen.com) | 
														
													
														
															
																|  |  | * |  |  | * | 
														
													
												
													
														
															
																|  | @@ -63,6 +63,7 @@ typedef struct ArgoASFDemuxContext { | 
														
													
														
															
																|  |  | uint32_t            blocks_read; |  |  | uint32_t            blocks_read; | 
														
													
														
															
																|  |  | } ArgoASFDemuxContext; |  |  | } ArgoASFDemuxContext; | 
														
													
														
															
																|  |  | 
 |  |  | 
 | 
														
													
														
															
																|  |  |  |  |  | #if CONFIG_ARGO_ASF_DEMUXER | 
														
													
														
															
																|  |  | static void argo_asf_parse_file_header(ArgoASFFileHeader *hdr, const uint8_t *buf) |  |  | static void argo_asf_parse_file_header(ArgoASFFileHeader *hdr, const uint8_t *buf) | 
														
													
														
															
																|  |  | { |  |  | { | 
														
													
														
															
																|  |  | hdr->magic          = AV_RL32(buf + 0); |  |  | hdr->magic          = AV_RL32(buf + 0); | 
														
													
												
													
														
															
																|  | @@ -254,3 +255,127 @@ AVInputFormat ff_argo_asf_demuxer = { | 
														
													
														
															
																|  |  | .read_header    = argo_asf_read_header, |  |  | .read_header    = argo_asf_read_header, | 
														
													
														
															
																|  |  | .read_packet    = argo_asf_read_packet |  |  | .read_packet    = argo_asf_read_packet | 
														
													
														
															
																|  |  | }; |  |  | }; | 
														
													
														
															
																|  |  |  |  |  | #endif | 
														
													
														
															
																|  |  |  |  |  | 
 | 
														
													
														
															
																|  |  |  |  |  | #if CONFIG_ARGO_ASF_MUXER | 
														
													
														
															
																|  |  |  |  |  | static int argo_asf_write_init(AVFormatContext *s) | 
														
													
														
															
																|  |  |  |  |  | { | 
														
													
														
															
																|  |  |  |  |  | const AVCodecParameters *par; | 
														
													
														
															
																|  |  |  |  |  | 
 | 
														
													
														
															
																|  |  |  |  |  | if (s->nb_streams != 1) { | 
														
													
														
															
																|  |  |  |  |  | av_log(s, AV_LOG_ERROR, "ASF files have exactly one stream\n"); | 
														
													
														
															
																|  |  |  |  |  | return AVERROR(EINVAL); | 
														
													
														
															
																|  |  |  |  |  | } | 
														
													
														
															
																|  |  |  |  |  | 
 | 
														
													
														
															
																|  |  |  |  |  | par = s->streams[0]->codecpar; | 
														
													
														
															
																|  |  |  |  |  | 
 | 
														
													
														
															
																|  |  |  |  |  | if (par->codec_id != AV_CODEC_ID_ADPCM_ARGO) { | 
														
													
														
															
																|  |  |  |  |  | av_log(s, AV_LOG_ERROR, "%s codec not supported\n", | 
														
													
														
															
																|  |  |  |  |  | avcodec_get_name(par->codec_id)); | 
														
													
														
															
																|  |  |  |  |  | return AVERROR(EINVAL); | 
														
													
														
															
																|  |  |  |  |  | } | 
														
													
														
															
																|  |  |  |  |  | 
 | 
														
													
														
															
																|  |  |  |  |  | if (par->channels > 2) { | 
														
													
														
															
																|  |  |  |  |  | av_log(s, AV_LOG_ERROR, "ASF files only support up to 2 channels\n"); | 
														
													
														
															
																|  |  |  |  |  | return AVERROR(EINVAL); | 
														
													
														
															
																|  |  |  |  |  | } | 
														
													
														
															
																|  |  |  |  |  | 
 | 
														
													
														
															
																|  |  |  |  |  | if (par->sample_rate > UINT16_MAX) { | 
														
													
														
															
																|  |  |  |  |  | av_log(s, AV_LOG_ERROR, "Sample rate too large\n"); | 
														
													
														
															
																|  |  |  |  |  | return AVERROR(EINVAL); | 
														
													
														
															
																|  |  |  |  |  | } | 
														
													
														
															
																|  |  |  |  |  | 
 | 
														
													
														
															
																|  |  |  |  |  | if (!(s->pb->seekable & AVIO_SEEKABLE_NORMAL)) { | 
														
													
														
															
																|  |  |  |  |  | av_log(s, AV_LOG_ERROR, "Stream not seekable, unable to write output file\n"); | 
														
													
														
															
																|  |  |  |  |  | return AVERROR(EINVAL); | 
														
													
														
															
																|  |  |  |  |  | } | 
														
													
														
															
																|  |  |  |  |  | 
 | 
														
													
														
															
																|  |  |  |  |  | return 0; | 
														
													
														
															
																|  |  |  |  |  | } | 
														
													
														
															
																|  |  |  |  |  | 
 | 
														
													
														
															
																|  |  |  |  |  | static void argo_asf_write_file_header(const ArgoASFFileHeader *fhdr, AVIOContext *pb) | 
														
													
														
															
																|  |  |  |  |  | { | 
														
													
														
															
																|  |  |  |  |  | avio_wl32( pb, fhdr->magic); | 
														
													
														
															
																|  |  |  |  |  | avio_wl16( pb, fhdr->version_major); | 
														
													
														
															
																|  |  |  |  |  | avio_wl16( pb, fhdr->version_minor); | 
														
													
														
															
																|  |  |  |  |  | avio_wl32( pb, fhdr->num_chunks); | 
														
													
														
															
																|  |  |  |  |  | avio_wl32( pb, fhdr->chunk_offset); | 
														
													
														
															
																|  |  |  |  |  | avio_write(pb, fhdr->name, sizeof(fhdr->name)); | 
														
													
														
															
																|  |  |  |  |  | } | 
														
													
														
															
																|  |  |  |  |  | 
 | 
														
													
														
															
																|  |  |  |  |  | static void argo_asf_write_chunk_header(const ArgoASFChunkHeader *ckhdr, AVIOContext *pb) | 
														
													
														
															
																|  |  |  |  |  | { | 
														
													
														
															
																|  |  |  |  |  | avio_wl32(pb, ckhdr->num_blocks); | 
														
													
														
															
																|  |  |  |  |  | avio_wl32(pb, ckhdr->num_samples); | 
														
													
														
															
																|  |  |  |  |  | avio_wl32(pb, ckhdr->unk1); | 
														
													
														
															
																|  |  |  |  |  | avio_wl16(pb, ckhdr->sample_rate); | 
														
													
														
															
																|  |  |  |  |  | avio_wl16(pb, ckhdr->unk2); | 
														
													
														
															
																|  |  |  |  |  | avio_wl32(pb, ckhdr->flags); | 
														
													
														
															
																|  |  |  |  |  | } | 
														
													
														
															
																|  |  |  |  |  | 
 | 
														
													
														
															
																|  |  |  |  |  | static int argo_asf_write_header(AVFormatContext *s) | 
														
													
														
															
																|  |  |  |  |  | { | 
														
													
														
															
																|  |  |  |  |  | const AVCodecParameters  *par = s->streams[0]->codecpar; | 
														
													
														
															
																|  |  |  |  |  | ArgoASFFileHeader  fhdr; | 
														
													
														
															
																|  |  |  |  |  | ArgoASFChunkHeader chdr; | 
														
													
														
															
																|  |  |  |  |  | 
 | 
														
													
														
															
																|  |  |  |  |  | fhdr.magic         = ASF_TAG; | 
														
													
														
															
																|  |  |  |  |  | fhdr.version_major = 2; | 
														
													
														
															
																|  |  |  |  |  | fhdr.version_minor = 1; | 
														
													
														
															
																|  |  |  |  |  | fhdr.num_chunks    = 1; | 
														
													
														
															
																|  |  |  |  |  | fhdr.chunk_offset  = ASF_FILE_HEADER_SIZE; | 
														
													
														
															
																|  |  |  |  |  | strncpy(fhdr.name, av_basename(s->url), FF_ARRAY_ELEMS(fhdr.name)); | 
														
													
														
															
																|  |  |  |  |  | 
 | 
														
													
														
															
																|  |  |  |  |  | chdr.num_blocks    = 0; | 
														
													
														
															
																|  |  |  |  |  | chdr.num_samples   = ASF_SAMPLE_COUNT; | 
														
													
														
															
																|  |  |  |  |  | chdr.unk1          = 0; | 
														
													
														
															
																|  |  |  |  |  | chdr.sample_rate   = par->sample_rate; | 
														
													
														
															
																|  |  |  |  |  | chdr.unk2          = ~0; | 
														
													
														
															
																|  |  |  |  |  | chdr.flags         = ASF_CF_BITS_PER_SAMPLE | ASF_CF_ALWAYS1; | 
														
													
														
															
																|  |  |  |  |  | 
 | 
														
													
														
															
																|  |  |  |  |  | if (par->channels == 2) | 
														
													
														
															
																|  |  |  |  |  | chdr.flags |= ASF_CF_STEREO; | 
														
													
														
															
																|  |  |  |  |  | 
 | 
														
													
														
															
																|  |  |  |  |  | argo_asf_write_file_header(&fhdr, s->pb); | 
														
													
														
															
																|  |  |  |  |  | argo_asf_write_chunk_header(&chdr, s->pb); | 
														
													
														
															
																|  |  |  |  |  | return 0; | 
														
													
														
															
																|  |  |  |  |  | } | 
														
													
														
															
																|  |  |  |  |  | 
 | 
														
													
														
															
																|  |  |  |  |  | static int argo_asf_write_packet(AVFormatContext *s, AVPacket *pkt) | 
														
													
														
															
																|  |  |  |  |  | { | 
														
													
														
															
																|  |  |  |  |  | if (pkt->size != 17 * s->streams[0]->codecpar->channels) | 
														
													
														
															
																|  |  |  |  |  | return AVERROR_INVALIDDATA; | 
														
													
														
															
																|  |  |  |  |  | 
 | 
														
													
														
															
																|  |  |  |  |  | if (s->streams[0]->nb_frames >= UINT32_MAX) | 
														
													
														
															
																|  |  |  |  |  | return AVERROR_INVALIDDATA; | 
														
													
														
															
																|  |  |  |  |  | 
 | 
														
													
														
															
																|  |  |  |  |  | avio_write(s->pb, pkt->data, pkt->size); | 
														
													
														
															
																|  |  |  |  |  | return 0; | 
														
													
														
															
																|  |  |  |  |  | } | 
														
													
														
															
																|  |  |  |  |  | 
 | 
														
													
														
															
																|  |  |  |  |  | static int argo_asf_write_trailer(AVFormatContext *s) | 
														
													
														
															
																|  |  |  |  |  | { | 
														
													
														
															
																|  |  |  |  |  | int64_t ret; | 
														
													
														
															
																|  |  |  |  |  | 
 | 
														
													
														
															
																|  |  |  |  |  | if ((ret = avio_seek(s->pb, ASF_FILE_HEADER_SIZE, SEEK_SET) < 0)) | 
														
													
														
															
																|  |  |  |  |  | return ret; | 
														
													
														
															
																|  |  |  |  |  | 
 | 
														
													
														
															
																|  |  |  |  |  | avio_wl32(s->pb, (uint32_t)s->streams[0]->nb_frames); | 
														
													
														
															
																|  |  |  |  |  | return 0; | 
														
													
														
															
																|  |  |  |  |  | } | 
														
													
														
															
																|  |  |  |  |  | 
 | 
														
													
														
															
																|  |  |  |  |  | AVOutputFormat ff_argo_asf_muxer = { | 
														
													
														
															
																|  |  |  |  |  | .name           = "argo_asf", | 
														
													
														
															
																|  |  |  |  |  | .long_name      = NULL_IF_CONFIG_SMALL("Argonaut Games ASF"), | 
														
													
														
															
																|  |  |  |  |  | /* | 
														
													
														
															
																|  |  |  |  |  | * NB: Can't do this as it conflicts with the actual ASF format. | 
														
													
														
															
																|  |  |  |  |  | * .extensions  = "asf", | 
														
													
														
															
																|  |  |  |  |  | */ | 
														
													
														
															
																|  |  |  |  |  | .audio_codec    = AV_CODEC_ID_ADPCM_ARGO, | 
														
													
														
															
																|  |  |  |  |  | .video_codec    = AV_CODEC_ID_NONE, | 
														
													
														
															
																|  |  |  |  |  | .init           = argo_asf_write_init, | 
														
													
														
															
																|  |  |  |  |  | .write_header   = argo_asf_write_header, | 
														
													
														
															
																|  |  |  |  |  | .write_packet   = argo_asf_write_packet, | 
														
													
														
															
																|  |  |  |  |  | .write_trailer  = argo_asf_write_trailer | 
														
													
														
															
																|  |  |  |  |  | }; | 
														
													
														
															
																|  |  |  |  |  | #endif |