Mercurial > libavformat.hg
comparison mxfenc.c @ 4312:385b2fdccbbb libavformat
correctly pack and interleave pcm samples in mxf
author | bcoudurier |
---|---|
date | Sat, 31 Jan 2009 06:18:25 +0000 |
parents | 2402eb8c37ff |
children | bdb984bfa3ed |
comparison
equal
deleted
inserted
replaced
4311:03065a598506 | 4312:385b2fdccbbb |
---|---|
29 * SMPTE RP224: Registry of SMPTE Universal Labels | 29 * SMPTE RP224: Registry of SMPTE Universal Labels |
30 */ | 30 */ |
31 | 31 |
32 //#define DEBUG | 32 //#define DEBUG |
33 | 33 |
34 #include "libavutil/fifo.h" | |
34 #include "mxf.h" | 35 #include "mxf.h" |
36 | |
37 static const int NTSC_samples_per_frame[] = { 1602, 1601, 1602, 1601, 1602, 0 }; | |
38 static const int PAL_samples_per_frame[] = { 1920, 0 }; | |
39 | |
40 typedef struct { | |
41 AVFifoBuffer fifo; | |
42 unsigned fifo_size; ///< current fifo size allocated | |
43 uint64_t dts; ///< current dts | |
44 int sample_size; ///< size of one sample all channels included | |
45 const int *samples_per_frame; ///< must be 0 terminated | |
46 const int *samples; ///< current samples per frame, pointer to samples_per_frame | |
47 } AudioInterleaveContext; | |
35 | 48 |
36 typedef struct { | 49 typedef struct { |
37 int local_tag; | 50 int local_tag; |
38 UID uid; | 51 UID uid; |
39 } MXFLocalTagPair; | 52 } MXFLocalTagPair; |
40 | 53 |
41 typedef struct { | 54 typedef struct { |
55 AudioInterleaveContext aic; | |
42 UID track_essence_element_key; | 56 UID track_essence_element_key; |
43 int index; //<<< index in mxf_essence_container_uls table | 57 int index; //<<< index in mxf_essence_container_uls table |
44 const UID *codec_ul; | 58 const UID *codec_ul; |
45 int64_t duration; | 59 int64_t duration; |
60 int order; ///< interleaving order if dts are equal | |
46 } MXFStreamContext; | 61 } MXFStreamContext; |
47 | 62 |
48 typedef struct { | 63 typedef struct { |
49 UID container_ul; | 64 UID container_ul; |
50 UID element_ul; | 65 UID element_ul; |
73 | 88 |
74 typedef struct MXFContext { | 89 typedef struct MXFContext { |
75 int64_t footer_partition_offset; | 90 int64_t footer_partition_offset; |
76 int essence_container_count; | 91 int essence_container_count; |
77 uint8_t essence_containers_indices[FF_ARRAY_ELEMS(mxf_essence_container_uls)]; | 92 uint8_t essence_containers_indices[FF_ARRAY_ELEMS(mxf_essence_container_uls)]; |
93 AVRational time_base; | |
78 } MXFContext; | 94 } MXFContext; |
79 | 95 |
80 static const uint8_t uuid_base[] = { 0xAD,0xAB,0x44,0x24,0x2f,0x25,0x4d,0xc7,0x92,0xff,0x29,0xbd }; | 96 static const uint8_t uuid_base[] = { 0xAD,0xAB,0x44,0x24,0x2f,0x25,0x4d,0xc7,0x92,0xff,0x29,0xbd }; |
81 static const uint8_t umid_base[] = { 0x06,0x0A,0x2B,0x34,0x01,0x01,0x01,0x05,0x01,0x01,0x0D,0x00,0x13,0x00,0x00,0x00 }; | 97 static const uint8_t umid_base[] = { 0x06,0x0A,0x2B,0x34,0x01,0x01,0x01,0x05,0x01,0x01,0x0D,0x00,0x13,0x00,0x00,0x00 }; |
82 | 98 |
779 &mxf_mpeg2_codec_uls[6]; | 795 &mxf_mpeg2_codec_uls[6]; |
780 } | 796 } |
781 return NULL; | 797 return NULL; |
782 } | 798 } |
783 | 799 |
800 static int ff_audio_interleave_init(AVFormatContext *s, const int *samples_per_frame) | |
801 { | |
802 int i; | |
803 | |
804 if (!samples_per_frame) | |
805 samples_per_frame = PAL_samples_per_frame; | |
806 | |
807 for (i = 0; i < s->nb_streams; i++) { | |
808 AVStream *st = s->streams[i]; | |
809 AudioInterleaveContext *aic = st->priv_data; | |
810 | |
811 if (st->codec->codec_type == CODEC_TYPE_AUDIO) { | |
812 aic->sample_size = (st->codec->channels * | |
813 av_get_bits_per_sample(st->codec->codec_id)) / 8; | |
814 if (!aic->sample_size) { | |
815 av_log(s, AV_LOG_ERROR, "could not compute sample size\n"); | |
816 return -1; | |
817 } | |
818 aic->samples_per_frame = samples_per_frame; | |
819 aic->samples = aic->samples_per_frame; | |
820 | |
821 av_fifo_init(&aic->fifo, 100 * *aic->samples); | |
822 } | |
823 } | |
824 | |
825 return 0; | |
826 } | |
827 | |
784 static int mxf_write_header(AVFormatContext *s) | 828 static int mxf_write_header(AVFormatContext *s) |
785 { | 829 { |
786 MXFContext *mxf = s->priv_data; | 830 MXFContext *mxf = s->priv_data; |
787 int i; | 831 int i; |
788 uint8_t present[FF_ARRAY_ELEMS(mxf_essence_container_uls)] = {0}; | 832 uint8_t present[FF_ARRAY_ELEMS(mxf_essence_container_uls)] = {0}; |
833 const int *samples_per_frame = NULL; | |
789 | 834 |
790 for (i = 0; i < s->nb_streams; i++) { | 835 for (i = 0; i < s->nb_streams; i++) { |
791 AVStream *st = s->streams[i]; | 836 AVStream *st = s->streams[i]; |
792 MXFStreamContext *sc = av_mallocz(sizeof(*sc)); | 837 MXFStreamContext *sc = av_mallocz(sizeof(*sc)); |
793 if (!sc) | 838 if (!sc) |
794 return AVERROR(ENOMEM); | 839 return AVERROR(ENOMEM); |
795 st->priv_data = sc; | 840 st->priv_data = sc; |
796 // set pts information | 841 |
797 if (st->codec->codec_type == CODEC_TYPE_VIDEO) | 842 if (st->codec->codec_type == CODEC_TYPE_VIDEO) { |
798 av_set_pts_info(st, 64, 1, st->codec->time_base.den); | 843 if (!av_cmp_q(st->codec->time_base, (AVRational){ 1, 25 })) { |
799 else if (st->codec->codec_type == CODEC_TYPE_AUDIO) | 844 samples_per_frame = PAL_samples_per_frame; |
800 av_set_pts_info(st, 64, 1, st->codec->sample_rate); | 845 mxf->time_base = (AVRational){ 1, 25 }; |
846 } else if (!av_cmp_q(st->codec->time_base, (AVRational){ 1001, 30000 })) { | |
847 samples_per_frame = NTSC_samples_per_frame; | |
848 mxf->time_base = (AVRational){ 1001, 30000 }; | |
849 } else { | |
850 av_log(s, AV_LOG_ERROR, "unsupported video frame rate\n"); | |
851 return -1; | |
852 } | |
853 } else if (st->codec->codec_type == CODEC_TYPE_AUDIO) { | |
854 if (st->codec->sample_rate != 48000) { | |
855 av_log(s, AV_LOG_ERROR, "only 48khz is implemented\n"); | |
856 return -1; | |
857 } | |
858 } | |
801 sc->duration = -1; | 859 sc->duration = -1; |
802 | 860 |
803 sc->index = mxf_get_essence_container_ul_index(st->codec->codec_id); | 861 sc->index = mxf_get_essence_container_ul_index(st->codec->codec_id); |
804 if (sc->index == -1) { | 862 if (sc->index == -1) { |
805 av_log(s, AV_LOG_ERROR, "track %d: could not find essence container ul, " | 863 av_log(s, AV_LOG_ERROR, "track %d: could not find essence container ul, " |
830 memcpy(sc->track_essence_element_key, mxf_essence_container_uls[sc->index].element_ul, 15); | 888 memcpy(sc->track_essence_element_key, mxf_essence_container_uls[sc->index].element_ul, 15); |
831 sc->track_essence_element_key[15] = present[sc->index]; | 889 sc->track_essence_element_key[15] = present[sc->index]; |
832 PRINT_KEY(s, "track essence element key", sc->track_essence_element_key); | 890 PRINT_KEY(s, "track essence element key", sc->track_essence_element_key); |
833 } | 891 } |
834 | 892 |
893 for (i = 0; i < s->nb_streams; i++) { | |
894 MXFStreamContext *sc = s->streams[i]->priv_data; | |
895 av_set_pts_info(s->streams[i], 64, mxf->time_base.num, mxf->time_base.den); | |
896 // update element count | |
897 sc->track_essence_element_key[13] = present[sc->index]; | |
898 sc->order = AV_RB32(sc->track_essence_element_key+12); | |
899 } | |
900 | |
901 if (ff_audio_interleave_init(s, samples_per_frame) < 0) | |
902 return -1; | |
903 | |
835 mxf_write_partition(s, 1, header_open_partition_key, 1); | 904 mxf_write_partition(s, 1, header_open_partition_key, 1); |
836 | 905 |
837 return 0; | 906 return 0; |
838 } | 907 } |
839 | 908 |
864 url_fseek(pb, 0, SEEK_SET); | 933 url_fseek(pb, 0, SEEK_SET); |
865 mxf_write_partition(s, 1, header_closed_partition_key, 1); | 934 mxf_write_partition(s, 1, header_closed_partition_key, 1); |
866 } | 935 } |
867 mxf_free(s); | 936 mxf_free(s); |
868 return 0; | 937 return 0; |
938 } | |
939 | |
940 static int mxf_interleave_new_audio_packet(AVFormatContext *s, AVPacket *pkt, | |
941 int stream_index, int flush) | |
942 { | |
943 AVStream *st = s->streams[stream_index]; | |
944 AudioInterleaveContext *aic = st->priv_data; | |
945 | |
946 int size = FFMIN(av_fifo_size(&aic->fifo), *aic->samples * aic->sample_size); | |
947 if (!size || (!flush && size == av_fifo_size(&aic->fifo))) | |
948 return 0; | |
949 | |
950 av_new_packet(pkt, size); | |
951 av_fifo_read(&aic->fifo, pkt->data, size); | |
952 | |
953 pkt->dts = pkt->pts = aic->dts; | |
954 pkt->duration = av_rescale_q(*aic->samples, | |
955 (AVRational){ 1, st->codec->sample_rate }, | |
956 st->time_base); | |
957 pkt->stream_index = stream_index; | |
958 aic->dts += pkt->duration; | |
959 | |
960 aic->samples++; | |
961 if (!*aic->samples) | |
962 aic->samples = aic->samples_per_frame; | |
963 | |
964 return size; | |
965 } | |
966 | |
967 static int mxf_interleave_get_packet(AVFormatContext *s, AVPacket *out, int flush) | |
968 { | |
969 AVPacketList *pktl; | |
970 int stream_count = 0; | |
971 int streams[MAX_STREAMS]; | |
972 | |
973 memset(streams, 0, sizeof(streams)); | |
974 pktl = s->packet_buffer; | |
975 while (pktl) { | |
976 //av_log(s, AV_LOG_DEBUG, "show st:%d dts:%lld\n", pktl->pkt.stream_index, pktl->pkt.dts); | |
977 if (!streams[pktl->pkt.stream_index]) | |
978 stream_count++; | |
979 streams[pktl->pkt.stream_index]++; | |
980 pktl = pktl->next; | |
981 } | |
982 | |
983 if (stream_count && (s->nb_streams == stream_count || flush)) { | |
984 pktl = s->packet_buffer; | |
985 *out = pktl->pkt; | |
986 //av_log(s, AV_LOG_DEBUG, "out st:%d dts:%lld\n", (*out).stream_index, (*out).dts); | |
987 s->packet_buffer = pktl->next; | |
988 av_freep(&pktl); | |
989 | |
990 if (flush && stream_count < s->nb_streams) { | |
991 // purge packet queue | |
992 pktl = s->packet_buffer; | |
993 while (pktl) { | |
994 AVPacketList *next = pktl->next; | |
995 av_free_packet(&pktl->pkt); | |
996 av_freep(&pktl); | |
997 pktl = next; | |
998 } | |
999 s->packet_buffer = NULL; | |
1000 } | |
1001 | |
1002 return 1; | |
1003 } else { | |
1004 av_init_packet(out); | |
1005 return 0; | |
1006 } | |
1007 } | |
1008 | |
1009 static int mxf_compare_timestamps(AVFormatContext *s, AVPacket *next, AVPacket *pkt) | |
1010 { | |
1011 AVStream *st = s->streams[pkt ->stream_index]; | |
1012 AVStream *st2 = s->streams[next->stream_index]; | |
1013 MXFStreamContext *sc = st ->priv_data; | |
1014 MXFStreamContext *sc2 = st2->priv_data; | |
1015 | |
1016 int64_t left = st2->time_base.num * (int64_t)st ->time_base.den; | |
1017 int64_t right = st ->time_base.num * (int64_t)st2->time_base.den; | |
1018 | |
1019 return next->dts * left > pkt->dts * right || // FIXME this can overflow | |
1020 (next->dts * left == pkt->dts * right && sc->order < sc2->order); | |
1021 } | |
1022 | |
1023 static int mxf_interleave(AVFormatContext *s, AVPacket *out, AVPacket *pkt, int flush) | |
1024 { | |
1025 int i; | |
1026 | |
1027 if (pkt) { | |
1028 AVStream *st = s->streams[pkt->stream_index]; | |
1029 AudioInterleaveContext *aic = st->priv_data; | |
1030 if (st->codec->codec_type == CODEC_TYPE_AUDIO) { | |
1031 av_fifo_generic_write(&aic->fifo, pkt->data, pkt->size, NULL); | |
1032 } else { | |
1033 // rewrite pts and dts to be decoded time line position | |
1034 pkt->pts = pkt->dts = aic->dts; | |
1035 aic->dts += pkt->duration; | |
1036 ff_interleave_add_packet(s, pkt, mxf_compare_timestamps); | |
1037 } | |
1038 } | |
1039 | |
1040 for (i = 0; i < s->nb_streams; i++) { | |
1041 AVStream *st = s->streams[i]; | |
1042 if (st->codec->codec_type == CODEC_TYPE_AUDIO) { | |
1043 AVPacket new_pkt; | |
1044 while (mxf_interleave_new_audio_packet(s, &new_pkt, i, flush)) | |
1045 ff_interleave_add_packet(s, &new_pkt, mxf_compare_timestamps); | |
1046 } | |
1047 } | |
1048 | |
1049 return mxf_interleave_get_packet(s, out, flush); | |
869 } | 1050 } |
870 | 1051 |
871 AVOutputFormat mxf_muxer = { | 1052 AVOutputFormat mxf_muxer = { |
872 "mxf", | 1053 "mxf", |
873 NULL_IF_CONFIG_SMALL("Material eXchange Format"), | 1054 NULL_IF_CONFIG_SMALL("Material eXchange Format"), |
877 CODEC_ID_PCM_S16LE, | 1058 CODEC_ID_PCM_S16LE, |
878 CODEC_ID_MPEG2VIDEO, | 1059 CODEC_ID_MPEG2VIDEO, |
879 mxf_write_header, | 1060 mxf_write_header, |
880 mxf_write_packet, | 1061 mxf_write_packet, |
881 mxf_write_footer, | 1062 mxf_write_footer, |
1063 0, | |
1064 NULL, | |
1065 mxf_interleave, | |
882 }; | 1066 }; |
883 | 1067 |
884 | 1068 |