Mercurial > libavformat.hg
comparison movenc.c @ 4193:2d3be324c648 libavformat
Add support for muxing mov/mp4/3gp timed text streams
author | conrad |
---|---|
date | Sun, 11 Jan 2009 10:26:44 +0000 |
parents | 82cbec030af5 |
children | 67ab85a3611d |
comparison
equal
deleted
inserted
replaced
4192:a48a6a414dfe | 4193:2d3be324c648 |
---|---|
548 { CODEC_ID_H264, MKTAG('a','v','c','1') }, | 548 { CODEC_ID_H264, MKTAG('a','v','c','1') }, |
549 { CODEC_ID_MPEG4, MKTAG('m','p','4','v') }, | 549 { CODEC_ID_MPEG4, MKTAG('m','p','4','v') }, |
550 { CODEC_ID_AAC, MKTAG('m','p','4','a') }, | 550 { CODEC_ID_AAC, MKTAG('m','p','4','a') }, |
551 { CODEC_ID_AMR_NB, MKTAG('s','a','m','r') }, | 551 { CODEC_ID_AMR_NB, MKTAG('s','a','m','r') }, |
552 { CODEC_ID_AMR_WB, MKTAG('s','a','w','b') }, | 552 { CODEC_ID_AMR_WB, MKTAG('s','a','w','b') }, |
553 { CODEC_ID_MOV_TEXT, MKTAG('t', 'x', '3', 'g') }, | |
553 { CODEC_ID_NONE, 0 }, | 554 { CODEC_ID_NONE, 0 }, |
554 }; | 555 }; |
555 | 556 |
556 static const AVCodecTag mov_pix_fmt_tags[] = { | 557 static const AVCodecTag mov_pix_fmt_tags[] = { |
557 { PIX_FMT_YUYV422, MKTAG('y','u','v','s') }, | 558 { PIX_FMT_YUYV422, MKTAG('y','u','v','s') }, |
565 { CODEC_ID_H264, MKTAG('a','v','c','1') }, | 566 { CODEC_ID_H264, MKTAG('a','v','c','1') }, |
566 { CODEC_ID_MPEG4, MKTAG('m','p','4','v') }, | 567 { CODEC_ID_MPEG4, MKTAG('m','p','4','v') }, |
567 { CODEC_ID_AAC, MKTAG('m','p','4','a') }, | 568 { CODEC_ID_AAC, MKTAG('m','p','4','a') }, |
568 { CODEC_ID_ALAC, MKTAG('a','l','a','c') }, | 569 { CODEC_ID_ALAC, MKTAG('a','l','a','c') }, |
569 { CODEC_ID_AC3, MKTAG('a','c','-','3') }, | 570 { CODEC_ID_AC3, MKTAG('a','c','-','3') }, |
571 { CODEC_ID_MOV_TEXT, MKTAG('t', 'x', '3', 'g') }, | |
570 { CODEC_ID_NONE, 0 }, | 572 { CODEC_ID_NONE, 0 }, |
571 }; | 573 }; |
572 | 574 |
573 static int mov_find_codec_tag(AVFormatContext *s, MOVTrack *track) | 575 static int mov_find_codec_tag(AVFormatContext *s, MOVTrack *track) |
574 { | 576 { |
577 if (!codec_get_tag(ff_mp4_obj_type, track->enc->codec_id)) | 579 if (!codec_get_tag(ff_mp4_obj_type, track->enc->codec_id)) |
578 return 0; | 580 return 0; |
579 if (track->enc->codec_id == CODEC_ID_H264) tag = MKTAG('a','v','c','1'); | 581 if (track->enc->codec_id == CODEC_ID_H264) tag = MKTAG('a','v','c','1'); |
580 else if (track->enc->codec_id == CODEC_ID_AC3) tag = MKTAG('a','c','-','3'); | 582 else if (track->enc->codec_id == CODEC_ID_AC3) tag = MKTAG('a','c','-','3'); |
581 else if (track->enc->codec_id == CODEC_ID_DIRAC) tag = MKTAG('d','r','a','c'); | 583 else if (track->enc->codec_id == CODEC_ID_DIRAC) tag = MKTAG('d','r','a','c'); |
584 else if (track->enc->codec_id == CODEC_ID_MOV_TEXT) tag = MKTAG('t','x','3','g'); | |
582 else if (track->enc->codec_type == CODEC_TYPE_VIDEO) tag = MKTAG('m','p','4','v'); | 585 else if (track->enc->codec_type == CODEC_TYPE_VIDEO) tag = MKTAG('m','p','4','v'); |
583 else if (track->enc->codec_type == CODEC_TYPE_AUDIO) tag = MKTAG('m','p','4','a'); | 586 else if (track->enc->codec_type == CODEC_TYPE_AUDIO) tag = MKTAG('m','p','4','a'); |
584 } else if (track->mode == MODE_IPOD) { | 587 } else if (track->mode == MODE_IPOD) { |
585 tag = codec_get_tag(codec_ipod_tags, track->enc->codec_id); | 588 tag = codec_get_tag(codec_ipod_tags, track->enc->codec_id); |
586 if (!match_ext(s->filename, "m4a") && !match_ext(s->filename, "m4v")) | 589 if (!match_ext(s->filename, "m4a") && !match_ext(s->filename, "m4v")) |
619 tag = MKTAG('m', 's', ((ms_tag >> 8) & 0xff), (ms_tag & 0xff)); | 622 tag = MKTAG('m', 's', ((ms_tag >> 8) & 0xff), (ms_tag & 0xff)); |
620 av_log(s, AV_LOG_INFO, "Warning, using MS style audio codec tag, " | 623 av_log(s, AV_LOG_INFO, "Warning, using MS style audio codec tag, " |
621 "the file may be unplayable!\n"); | 624 "the file may be unplayable!\n"); |
622 } | 625 } |
623 } | 626 } |
627 } else if (track->enc->codec_type == CODEC_TYPE_SUBTITLE) { | |
628 tag = codec_get_tag(ff_codec_movsubtitle_tags, track->enc->codec_id); | |
624 } | 629 } |
625 } | 630 } |
626 } | 631 } |
627 return tag; | 632 return tag; |
628 } | 633 } |
639 put_be32(pb, 0x5f244fc5); | 644 put_be32(pb, 0x5f244fc5); |
640 put_be32(pb, 0xba39a51b); | 645 put_be32(pb, 0xba39a51b); |
641 put_be32(pb, 0xcf0323f3); | 646 put_be32(pb, 0xcf0323f3); |
642 put_be32(pb, 0x0); | 647 put_be32(pb, 0x0); |
643 return 28; | 648 return 28; |
649 } | |
650 | |
651 static int mov_write_subtitle_tag(ByteIOContext *pb, MOVTrack *track) | |
652 { | |
653 int64_t pos = url_ftell(pb); | |
654 put_be32(pb, 0); /* size */ | |
655 put_le32(pb, track->tag); // store it byteswapped | |
656 put_be32(pb, 0); /* Reserved */ | |
657 put_be16(pb, 0); /* Reserved */ | |
658 put_be16(pb, 1); /* Data-reference index */ | |
659 | |
660 if (track->enc->extradata_size) | |
661 put_buffer(pb, track->enc->extradata, track->enc->extradata_size); | |
662 | |
663 return updateSize(pb, pos); | |
644 } | 664 } |
645 | 665 |
646 static int mov_write_video_tag(ByteIOContext *pb, MOVTrack *track) | 666 static int mov_write_video_tag(ByteIOContext *pb, MOVTrack *track) |
647 { | 667 { |
648 int64_t pos = url_ftell(pb); | 668 int64_t pos = url_ftell(pb); |
716 put_be32(pb, 1); /* entry count */ | 736 put_be32(pb, 1); /* entry count */ |
717 if (track->enc->codec_type == CODEC_TYPE_VIDEO) | 737 if (track->enc->codec_type == CODEC_TYPE_VIDEO) |
718 mov_write_video_tag(pb, track); | 738 mov_write_video_tag(pb, track); |
719 else if (track->enc->codec_type == CODEC_TYPE_AUDIO) | 739 else if (track->enc->codec_type == CODEC_TYPE_AUDIO) |
720 mov_write_audio_tag(pb, track); | 740 mov_write_audio_tag(pb, track); |
741 else if (track->enc->codec_type == CODEC_TYPE_SUBTITLE) | |
742 mov_write_subtitle_tag(pb, track); | |
721 return updateSize(pb, pos); | 743 return updateSize(pb, pos); |
722 } | 744 } |
723 | 745 |
724 static int mov_write_ctts_tag(ByteIOContext *pb, MOVTrack *track) | 746 static int mov_write_ctts_tag(ByteIOContext *pb, MOVTrack *track) |
725 { | 747 { |
836 put_tag(pb, "dinf"); | 858 put_tag(pb, "dinf"); |
837 mov_write_dref_tag(pb); | 859 mov_write_dref_tag(pb); |
838 return updateSize(pb, pos); | 860 return updateSize(pb, pos); |
839 } | 861 } |
840 | 862 |
863 static int mov_write_nmhd_tag(ByteIOContext *pb) | |
864 { | |
865 put_be32(pb, 12); | |
866 put_tag(pb, "nmhd"); | |
867 put_be32(pb, 0); | |
868 return 12; | |
869 } | |
870 | |
871 static int mov_write_gmhd_tag(ByteIOContext *pb) | |
872 { | |
873 put_be32(pb, 0x20); /* size */ | |
874 put_tag(pb, "gmhd"); | |
875 put_be32(pb, 0x18); /* gmin size */ | |
876 put_tag(pb, "gmin"); /* generic media info */ | |
877 put_be32(pb, 0); /* version & flags */ | |
878 put_be16(pb, 0x40); /* graphics mode = */ | |
879 put_be16(pb, 0x8000); /* opColor (r?) */ | |
880 put_be16(pb, 0x8000); /* opColor (g?) */ | |
881 put_be16(pb, 0x8000); /* opColor (b?) */ | |
882 put_be16(pb, 0); /* balance */ | |
883 put_be16(pb, 0); /* reserved */ | |
884 return 0x20; | |
885 } | |
886 | |
841 static int mov_write_smhd_tag(ByteIOContext *pb) | 887 static int mov_write_smhd_tag(ByteIOContext *pb) |
842 { | 888 { |
843 put_be32(pb, 16); /* size */ | 889 put_be32(pb, 16); /* size */ |
844 put_tag(pb, "smhd"); | 890 put_tag(pb, "smhd"); |
845 put_be32(pb, 0); /* version & flags */ | 891 put_be32(pb, 0); /* version & flags */ |
869 } else { | 915 } else { |
870 hdlr = (track->mode == MODE_MOV) ? "mhlr" : "\0\0\0\0"; | 916 hdlr = (track->mode == MODE_MOV) ? "mhlr" : "\0\0\0\0"; |
871 if (track->enc->codec_type == CODEC_TYPE_VIDEO) { | 917 if (track->enc->codec_type == CODEC_TYPE_VIDEO) { |
872 hdlr_type = "vide"; | 918 hdlr_type = "vide"; |
873 descr = "VideoHandler"; | 919 descr = "VideoHandler"; |
874 } else { | 920 } else if (track->enc->codec_type == CODEC_TYPE_AUDIO){ |
875 hdlr_type = "soun"; | 921 hdlr_type = "soun"; |
876 descr = "SoundHandler"; | 922 descr = "SoundHandler"; |
923 } else if (track->enc->codec_type == CODEC_TYPE_SUBTITLE){ | |
924 if (track->mode == MODE_IPOD) hdlr_type = "sbtl"; | |
925 else hdlr_type = "text"; | |
926 descr = "SubtitleHandler"; | |
877 } | 927 } |
878 } | 928 } |
879 | 929 |
880 put_be32(pb, 0); /* size */ | 930 put_be32(pb, 0); /* size */ |
881 put_tag(pb, "hdlr"); | 931 put_tag(pb, "hdlr"); |
895 int64_t pos = url_ftell(pb); | 945 int64_t pos = url_ftell(pb); |
896 put_be32(pb, 0); /* size */ | 946 put_be32(pb, 0); /* size */ |
897 put_tag(pb, "minf"); | 947 put_tag(pb, "minf"); |
898 if(track->enc->codec_type == CODEC_TYPE_VIDEO) | 948 if(track->enc->codec_type == CODEC_TYPE_VIDEO) |
899 mov_write_vmhd_tag(pb); | 949 mov_write_vmhd_tag(pb); |
900 else | 950 else if (track->enc->codec_type == CODEC_TYPE_AUDIO) |
901 mov_write_smhd_tag(pb); | 951 mov_write_smhd_tag(pb); |
952 else if (track->enc->codec_type == CODEC_TYPE_SUBTITLE) { | |
953 if (track->mode == MODE_MOV) | |
954 mov_write_gmhd_tag(pb); | |
955 else | |
956 mov_write_nmhd_tag(pb); | |
957 } | |
902 if (track->mode == MODE_MOV) /* FIXME: Why do it for MODE_MOV only ? */ | 958 if (track->mode == MODE_MOV) /* FIXME: Why do it for MODE_MOV only ? */ |
903 mov_write_hdlr_tag(pb, NULL); | 959 mov_write_hdlr_tag(pb, NULL); |
904 mov_write_dinf_tag(pb); | 960 mov_write_dinf_tag(pb); |
905 mov_write_stbl_tag(pb, track); | 961 mov_write_stbl_tag(pb, track); |
906 return updateSize(pb, pos); | 962 return updateSize(pb, pos); |
987 put_be32(pb, 0x0); /* reserved */ | 1043 put_be32(pb, 0x0); /* reserved */ |
988 put_be32(pb, 0x0); /* reserved */ | 1044 put_be32(pb, 0x0); /* reserved */ |
989 put_be32(pb, 0x40000000); /* reserved */ | 1045 put_be32(pb, 0x40000000); /* reserved */ |
990 | 1046 |
991 /* Track width and height, for visual only */ | 1047 /* Track width and height, for visual only */ |
992 if(track->enc->codec_type == CODEC_TYPE_VIDEO) { | 1048 if(track->enc->codec_type == CODEC_TYPE_VIDEO || |
1049 track->enc->codec_type == CODEC_TYPE_SUBTITLE) { | |
993 double sample_aspect_ratio = av_q2d(st->sample_aspect_ratio); | 1050 double sample_aspect_ratio = av_q2d(st->sample_aspect_ratio); |
994 if(!sample_aspect_ratio) sample_aspect_ratio = 1; | 1051 if(!sample_aspect_ratio) sample_aspect_ratio = 1; |
995 put_be32(pb, sample_aspect_ratio * track->enc->width*0x10000); | 1052 put_be32(pb, sample_aspect_ratio * track->enc->width*0x10000); |
996 put_be32(pb, track->enc->height*0x10000); | 1053 put_be32(pb, track->enc->height*0x10000); |
997 } | 1054 } |
1622 track->enc->codec_id == CODEC_ID_MP3 && track->enc->sample_rate < 16000){ | 1679 track->enc->codec_id == CODEC_ID_MP3 && track->enc->sample_rate < 16000){ |
1623 av_log(s, AV_LOG_ERROR, "track %d: muxing mp3 at %dhz is not supported\n", | 1680 av_log(s, AV_LOG_ERROR, "track %d: muxing mp3 at %dhz is not supported\n", |
1624 i, track->enc->sample_rate); | 1681 i, track->enc->sample_rate); |
1625 return -1; | 1682 return -1; |
1626 } | 1683 } |
1684 }else if(st->codec->codec_type == CODEC_TYPE_SUBTITLE){ | |
1685 track->timescale = st->codec->time_base.den; | |
1686 av_set_pts_info(st, 64, 1, st->codec->time_base.den); | |
1627 } | 1687 } |
1628 } | 1688 } |
1629 | 1689 |
1630 mov_write_mdat_tag(pb, mov); | 1690 mov_write_mdat_tag(pb, mov); |
1631 mov->time = s->timestamp + 0x7C25B080; //1970 based -> 1904 based | 1691 mov->time = s->timestamp + 0x7C25B080; //1970 based -> 1904 based |