正在显示
2 个修改的文件
包含
781 行增加
和
781 行删除
| @@ -858,858 +858,858 @@ int srs_rtmp_write_packet(srs_rtmp_t rtmp, char type, u_int32_t timestamp, char* | @@ -858,858 +858,858 @@ int srs_rtmp_write_packet(srs_rtmp_t rtmp, char type, u_int32_t timestamp, char* | ||
| 858 | return ret; | 858 | return ret; |
| 859 | } | 859 | } |
| 860 | 860 | ||
| 861 | -struct FlvContext | ||
| 862 | -{ | ||
| 863 | - SrsFileReader reader; | ||
| 864 | - SrsFileWriter writer; | ||
| 865 | - SrsFlvEncoder enc; | ||
| 866 | - SrsFlvDecoder dec; | ||
| 867 | -}; | ||
| 868 | - | ||
| 869 | -srs_flv_t srs_flv_open_read(const char* file) | ||
| 870 | -{ | ||
| 871 | - int ret = ERROR_SUCCESS; | ||
| 872 | - | ||
| 873 | - FlvContext* flv = new FlvContext(); | 861 | +/** |
| 862 | +* write audio raw frame to SRS. | ||
| 863 | +*/ | ||
| 864 | +int srs_audio_write_raw_frame(srs_rtmp_t rtmp, | ||
| 865 | + char sound_format, char sound_rate, char sound_size, char sound_type, | ||
| 866 | + char aac_packet_type, char* frame, int frame_size, u_int32_t timestamp | ||
| 867 | +) { | ||
| 868 | + Context* context = (Context*)rtmp; | ||
| 869 | + srs_assert(context); | ||
| 874 | 870 | ||
| 875 | - if ((ret = flv->reader.open(file)) != ERROR_SUCCESS) { | ||
| 876 | - srs_freep(flv); | ||
| 877 | - return NULL; | ||
| 878 | - } | 871 | + // TODO: FIXME: for aac, must send the sequence header first. |
| 879 | 872 | ||
| 880 | - if ((ret = flv->dec.initialize(&flv->reader)) != ERROR_SUCCESS) { | ||
| 881 | - srs_freep(flv); | ||
| 882 | - return NULL; | 873 | + // for audio frame, there is 1 or 2 bytes header: |
| 874 | + // 1bytes, SoundFormat|SoundRate|SoundSize|SoundType | ||
| 875 | + // 1bytes, AACPacketType for SoundFormat == 10 | ||
| 876 | + int size = frame_size + 1; | ||
| 877 | + if (aac_packet_type == SrsCodecAudioAAC) { | ||
| 878 | + size += 1; | ||
| 883 | } | 879 | } |
| 880 | + char* data = new char[size]; | ||
| 881 | + char* p = data; | ||
| 884 | 882 | ||
| 885 | - return flv; | ||
| 886 | -} | ||
| 887 | - | ||
| 888 | -srs_flv_t srs_flv_open_write(const char* file) | ||
| 889 | -{ | ||
| 890 | - int ret = ERROR_SUCCESS; | 883 | + u_int8_t audio_header = sound_type & 0x01; |
| 884 | + audio_header |= (sound_size << 1) & 0x02; | ||
| 885 | + audio_header |= (sound_rate << 2) & 0x0c; | ||
| 886 | + audio_header |= (sound_format << 4) & 0xf0; | ||
| 891 | 887 | ||
| 892 | - FlvContext* flv = new FlvContext(); | 888 | + *p++ = audio_header; |
| 893 | 889 | ||
| 894 | - if ((ret = flv->writer.open(file)) != ERROR_SUCCESS) { | ||
| 895 | - srs_freep(flv); | ||
| 896 | - return NULL; | 890 | + if (aac_packet_type == SrsCodecAudioAAC) { |
| 891 | + *p++ = aac_packet_type; | ||
| 897 | } | 892 | } |
| 898 | 893 | ||
| 899 | - if ((ret = flv->enc.initialize(&flv->writer)) != ERROR_SUCCESS) { | ||
| 900 | - srs_freep(flv); | ||
| 901 | - return NULL; | ||
| 902 | - } | 894 | + memcpy(p, frame, frame_size); |
| 903 | 895 | ||
| 904 | - return flv; | 896 | + return srs_rtmp_write_packet(context, SRS_RTMP_TYPE_AUDIO, timestamp, data, size); |
| 905 | } | 897 | } |
| 906 | 898 | ||
| 907 | -void srs_flv_close(srs_flv_t flv) | ||
| 908 | -{ | ||
| 909 | - FlvContext* context = (FlvContext*)flv; | ||
| 910 | - srs_freep(context); | ||
| 911 | -} | 899 | +/** |
| 900 | +* write h264 packet, with rtmp header. | ||
| 901 | +* @param frame_type, SrsCodecVideoAVCFrameKeyFrame or SrsCodecVideoAVCFrameInterFrame. | ||
| 902 | +* @param avc_packet_type, SrsCodecVideoAVCTypeSequenceHeader or SrsCodecVideoAVCTypeNALU. | ||
| 903 | +* @param h264_raw_data the h.264 raw data, user must free it. | ||
| 904 | +*/ | ||
| 905 | +int __srs_write_h264_packet(Context* context, | ||
| 906 | + int8_t frame_type, int8_t avc_packet_type, | ||
| 907 | + char* h264_raw_data, int h264_raw_size, u_int32_t dts, u_int32_t pts | ||
| 908 | +) { | ||
| 909 | + // the timestamp in rtmp message header is dts. | ||
| 910 | + u_int32_t timestamp = dts; | ||
| 912 | 911 | ||
| 913 | -int srs_flv_read_header(srs_flv_t flv, char header[9]) | ||
| 914 | -{ | ||
| 915 | - int ret = ERROR_SUCCESS; | 912 | + // for h264 in RTMP video payload, there is 5bytes header: |
| 913 | + // 1bytes, FrameType | CodecID | ||
| 914 | + // 1bytes, AVCPacketType | ||
| 915 | + // 3bytes, CompositionTime, the cts. | ||
| 916 | + // @see: E.4.3 Video Tags, video_file_format_spec_v10_1.pdf, page 78 | ||
| 917 | + int size = h264_raw_size + 5; | ||
| 918 | + char* data = new char[size]; | ||
| 919 | + char* p = data; | ||
| 916 | 920 | ||
| 917 | - FlvContext* context = (FlvContext*)flv; | 921 | + // @see: E.4.3 Video Tags, video_file_format_spec_v10_1.pdf, page 78 |
| 922 | + // Frame Type, Type of video frame. | ||
| 923 | + // CodecID, Codec Identifier. | ||
| 924 | + // set the rtmp header | ||
| 925 | + *p++ = (frame_type << 4) | SrsCodecVideoAVC; | ||
| 918 | 926 | ||
| 919 | - if (!context->reader.is_open()) { | ||
| 920 | - return ERROR_SYSTEM_IO_INVALID; | ||
| 921 | - } | 927 | + // AVCPacketType |
| 928 | + *p++ = avc_packet_type; | ||
| 922 | 929 | ||
| 923 | - if ((ret = context->dec.read_header(header)) != ERROR_SUCCESS) { | ||
| 924 | - return ret; | ||
| 925 | - } | 930 | + // CompositionTime |
| 931 | + // pts = dts + cts, or | ||
| 932 | + // cts = pts - dts. | ||
| 933 | + // where cts is the header in rtmp video packet payload header. | ||
| 934 | + u_int32_t cts = pts - dts; | ||
| 935 | + char* pp = (char*)&cts; | ||
| 936 | + *p++ = pp[2]; | ||
| 937 | + *p++ = pp[1]; | ||
| 938 | + *p++ = pp[0]; | ||
| 926 | 939 | ||
| 927 | - char ts[4]; // tag size | ||
| 928 | - if ((ret = context->dec.read_previous_tag_size(ts)) != ERROR_SUCCESS) { | ||
| 929 | - return ret; | ||
| 930 | - } | 940 | + // h.264 raw data. |
| 941 | + memcpy(p, h264_raw_data, h264_raw_size); | ||
| 931 | 942 | ||
| 932 | - return ret; | 943 | + return srs_rtmp_write_packet(context, SRS_RTMP_TYPE_VIDEO, timestamp, data, size); |
| 933 | } | 944 | } |
| 934 | 945 | ||
| 935 | -int srs_flv_read_tag_header(srs_flv_t flv, char* ptype, int32_t* pdata_size, u_int32_t* ptime) | 946 | +/** |
| 947 | +* write the h264 sps/pps in context over RTMP. | ||
| 948 | +*/ | ||
| 949 | +int __srs_write_h264_sps_pps(Context* context, u_int32_t dts, u_int32_t pts) | ||
| 936 | { | 950 | { |
| 937 | int ret = ERROR_SUCCESS; | 951 | int ret = ERROR_SUCCESS; |
| 938 | 952 | ||
| 939 | - FlvContext* context = (FlvContext*)flv; | ||
| 940 | - | ||
| 941 | - if (!context->reader.is_open()) { | ||
| 942 | - return ERROR_SYSTEM_IO_INVALID; | ||
| 943 | - } | ||
| 944 | - | ||
| 945 | - if ((ret = context->dec.read_tag_header(ptype, pdata_size, ptime)) != ERROR_SUCCESS) { | 953 | + // only send when both sps and pps changed. |
| 954 | + if (!context->h264_sps_changed || !context->h264_pps_changed) { | ||
| 946 | return ret; | 955 | return ret; |
| 947 | } | 956 | } |
| 948 | 957 | ||
| 958 | + // 5bytes sps/pps header: | ||
| 959 | + // configurationVersion, AVCProfileIndication, profile_compatibility, | ||
| 960 | + // AVCLevelIndication, lengthSizeMinusOne | ||
| 961 | + // 3bytes size of sps: | ||
| 962 | + // numOfSequenceParameterSets, sequenceParameterSetLength(2B) | ||
| 963 | + // Nbytes of sps. | ||
| 964 | + // sequenceParameterSetNALUnit | ||
| 965 | + // 3bytes size of pps: | ||
| 966 | + // numOfPictureParameterSets, pictureParameterSetLength | ||
| 967 | + // Nbytes of pps: | ||
| 968 | + // pictureParameterSetNALUnit | ||
| 969 | + int nb_packet = 5 | ||
| 970 | + + 3 + (int)context->h264_sps.length() | ||
| 971 | + + 3 + (int)context->h264_pps.length(); | ||
| 972 | + char* packet = new char[nb_packet]; | ||
| 973 | + SrsAutoFree(char, packet); | ||
| 974 | + | ||
| 975 | + // use stream to generate the h264 packet. | ||
| 976 | + SrsStream stream; | ||
| 977 | + if ((ret = stream.initialize(packet, nb_packet)) != ERROR_SUCCESS) { | ||
| 949 | return ret; | 978 | return ret; |
| 950 | -} | 979 | + } |
| 951 | 980 | ||
| 952 | -int srs_flv_read_tag_data(srs_flv_t flv, char* data, int32_t size) | ||
| 953 | -{ | ||
| 954 | - int ret = ERROR_SUCCESS; | 981 | + // decode the SPS: |
| 982 | + // @see: 7.3.2.1.1, H.264-AVC-ISO_IEC_14496-10-2012.pdf, page 62 | ||
| 983 | + if (true) { | ||
| 984 | + srs_assert((int)context->h264_sps.length() >= 4); | ||
| 985 | + char* frame = (char*)context->h264_sps.data(); | ||
| 955 | 986 | ||
| 956 | - FlvContext* context = (FlvContext*)flv; | 987 | + // @see: Annex A Profiles and levels, H.264-AVC-ISO_IEC_14496-10.pdf, page 205 |
| 988 | + // Baseline profile profile_idc is 66(0x42). | ||
| 989 | + // Main profile profile_idc is 77(0x4d). | ||
| 990 | + // Extended profile profile_idc is 88(0x58). | ||
| 991 | + u_int8_t profile_idc = frame[1]; | ||
| 992 | + //u_int8_t constraint_set = frame[2]; | ||
| 993 | + u_int8_t level_idc = frame[3]; | ||
| 957 | 994 | ||
| 958 | - if (!context->reader.is_open()) { | ||
| 959 | - return ERROR_SYSTEM_IO_INVALID; | 995 | + // generate the sps/pps header |
| 996 | + // 5.3.4.2.1 Syntax, H.264-AVC-ISO_IEC_14496-15.pdf, page 16 | ||
| 997 | + // configurationVersion | ||
| 998 | + stream.write_1bytes(0x01); | ||
| 999 | + // AVCProfileIndication | ||
| 1000 | + stream.write_1bytes(profile_idc); | ||
| 1001 | + // profile_compatibility | ||
| 1002 | + stream.write_1bytes(0x00); | ||
| 1003 | + // AVCLevelIndication | ||
| 1004 | + stream.write_1bytes(level_idc); | ||
| 1005 | + // lengthSizeMinusOne, or NAL_unit_length, always use 4bytes size, | ||
| 1006 | + // so we always set it to 0x03. | ||
| 1007 | + stream.write_1bytes(0x03); | ||
| 960 | } | 1008 | } |
| 961 | 1009 | ||
| 962 | - if ((ret = context->dec.read_tag_data(data, size)) != ERROR_SUCCESS) { | ||
| 963 | - return ret; | 1010 | + // sps |
| 1011 | + if (true) { | ||
| 1012 | + // 5.3.4.2.1 Syntax, H.264-AVC-ISO_IEC_14496-15.pdf, page 16 | ||
| 1013 | + // numOfSequenceParameterSets, always 1 | ||
| 1014 | + stream.write_1bytes(0x01); | ||
| 1015 | + // sequenceParameterSetLength | ||
| 1016 | + stream.write_2bytes(context->h264_sps.length()); | ||
| 1017 | + // sequenceParameterSetNALUnit | ||
| 1018 | + stream.write_string(context->h264_sps); | ||
| 964 | } | 1019 | } |
| 965 | 1020 | ||
| 966 | - char ts[4]; // tag size | ||
| 967 | - if ((ret = context->dec.read_previous_tag_size(ts)) != ERROR_SUCCESS) { | ||
| 968 | - return ret; | 1021 | + // pps |
| 1022 | + if (true) { | ||
| 1023 | + // 5.3.4.2.1 Syntax, H.264-AVC-ISO_IEC_14496-15.pdf, page 16 | ||
| 1024 | + // numOfPictureParameterSets, always 1 | ||
| 1025 | + stream.write_1bytes(0x01); | ||
| 1026 | + // pictureParameterSetLength | ||
| 1027 | + stream.write_2bytes(context->h264_pps.length()); | ||
| 1028 | + // pictureParameterSetNALUnit | ||
| 1029 | + stream.write_string(context->h264_pps); | ||
| 969 | } | 1030 | } |
| 970 | 1031 | ||
| 971 | - return ret; | ||
| 972 | -} | ||
| 973 | - | ||
| 974 | -int srs_flv_write_header(srs_flv_t flv, char header[9]) | ||
| 975 | -{ | ||
| 976 | - int ret = ERROR_SUCCESS; | ||
| 977 | - | ||
| 978 | - FlvContext* context = (FlvContext*)flv; | ||
| 979 | - | ||
| 980 | - if (!context->writer.is_open()) { | ||
| 981 | - return ERROR_SYSTEM_IO_INVALID; | ||
| 982 | - } | 1032 | + // reset sps and pps. |
| 1033 | + context->h264_sps_changed = false; | ||
| 1034 | + context->h264_pps_changed = false; | ||
| 1035 | + context->h264_sps_pps_sent = true; | ||
| 983 | 1036 | ||
| 984 | - if ((ret = context->enc.write_header(header)) != ERROR_SUCCESS) { | ||
| 985 | - return ret; | ||
| 986 | - } | 1037 | + // TODO: FIXME: for more profile. |
| 1038 | + // 5.3.4.2.1 Syntax, H.264-AVC-ISO_IEC_14496-15.pdf, page 16 | ||
| 1039 | + // profile_idc == 100 || profile_idc == 110 || profile_idc == 122 || profile_idc == 144 | ||
| 987 | 1040 | ||
| 988 | - return ret; | 1041 | + // send out h264 packet. |
| 1042 | + int8_t frame_type = SrsCodecVideoAVCFrameKeyFrame; | ||
| 1043 | + int8_t avc_packet_type = SrsCodecVideoAVCTypeSequenceHeader; | ||
| 1044 | + return __srs_write_h264_packet( | ||
| 1045 | + context, frame_type, avc_packet_type, | ||
| 1046 | + packet, nb_packet, dts, pts | ||
| 1047 | + ); | ||
| 989 | } | 1048 | } |
| 990 | 1049 | ||
| 991 | -int srs_flv_write_tag(srs_flv_t flv, char type, int32_t time, char* data, int size) | ||
| 992 | -{ | 1050 | +/** |
| 1051 | +* write h264 IPB-frame. | ||
| 1052 | +*/ | ||
| 1053 | +int __srs_write_h264_ipb_frame(Context* context, | ||
| 1054 | + char* data, int size, u_int32_t dts, u_int32_t pts | ||
| 1055 | +) { | ||
| 993 | int ret = ERROR_SUCCESS; | 1056 | int ret = ERROR_SUCCESS; |
| 994 | 1057 | ||
| 995 | - FlvContext* context = (FlvContext*)flv; | 1058 | + // when sps or pps not sent, ignore the packet. |
| 1059 | + // @see https://github.com/winlinvip/simple-rtmp-server/issues/203 | ||
| 1060 | + if (!context->h264_sps_pps_sent) { | ||
| 1061 | + return ERROR_H264_DROP_BEFORE_SPS_PPS; | ||
| 1062 | + } | ||
| 996 | 1063 | ||
| 997 | - if (!context->writer.is_open()) { | ||
| 998 | - return ERROR_SYSTEM_IO_INVALID; | 1064 | + // 5bits, 7.3.1 NAL unit syntax, |
| 1065 | + // H.264-AVC-ISO_IEC_14496-10.pdf, page 44. | ||
| 1066 | + // 7: SPS, 8: PPS, 5: I Frame, 1: P Frame | ||
| 1067 | + u_int8_t nal_unit_type = (char)data[0] & 0x1f; | ||
| 1068 | + | ||
| 1069 | + // 4bytes size of nalu: | ||
| 1070 | + // NALUnitLength | ||
| 1071 | + // Nbytes of nalu. | ||
| 1072 | + // NALUnit | ||
| 1073 | + int nb_packet = 4 + size; | ||
| 1074 | + char* packet = new char[nb_packet]; | ||
| 1075 | + SrsAutoFree(char, packet); | ||
| 1076 | + | ||
| 1077 | + // use stream to generate the h264 packet. | ||
| 1078 | + SrsStream stream; | ||
| 1079 | + if ((ret = stream.initialize(packet, nb_packet)) != ERROR_SUCCESS) { | ||
| 1080 | + return ret; | ||
| 999 | } | 1081 | } |
| 1000 | 1082 | ||
| 1001 | - if (type == SRS_RTMP_TYPE_AUDIO) { | ||
| 1002 | - return context->enc.write_audio(time, data, size); | ||
| 1003 | - } else if (type == SRS_RTMP_TYPE_VIDEO) { | ||
| 1004 | - return context->enc.write_video(time, data, size); | ||
| 1005 | - } else { | ||
| 1006 | - return context->enc.write_metadata(data, size); | 1083 | + // 5.3.4.2.1 Syntax, H.264-AVC-ISO_IEC_14496-15.pdf, page 16 |
| 1084 | + // lengthSizeMinusOne, or NAL_unit_length, always use 4bytes size | ||
| 1085 | + u_int32_t NAL_unit_length = size; | ||
| 1086 | + | ||
| 1087 | + // mux the avc NALU in "ISO Base Media File Format" | ||
| 1088 | + // from H.264-AVC-ISO_IEC_14496-15.pdf, page 20 | ||
| 1089 | + // NALUnitLength | ||
| 1090 | + stream.write_4bytes(NAL_unit_length); | ||
| 1091 | + // NALUnit | ||
| 1092 | + stream.write_bytes(data, size); | ||
| 1093 | + | ||
| 1094 | + // send out h264 packet. | ||
| 1095 | + int8_t frame_type = SrsCodecVideoAVCFrameInterFrame; | ||
| 1096 | + if (nal_unit_type != 1) { | ||
| 1097 | + frame_type = SrsCodecVideoAVCFrameKeyFrame; | ||
| 1007 | } | 1098 | } |
| 1099 | + int8_t avc_packet_type = SrsCodecVideoAVCTypeNALU; | ||
| 1100 | + return __srs_write_h264_packet( | ||
| 1101 | + context, frame_type, avc_packet_type, | ||
| 1102 | + packet, nb_packet, dts, pts | ||
| 1103 | + ); | ||
| 1008 | 1104 | ||
| 1009 | return ret; | 1105 | return ret; |
| 1010 | } | 1106 | } |
| 1011 | 1107 | ||
| 1012 | -int srs_flv_size_tag(int data_size) | ||
| 1013 | -{ | ||
| 1014 | - return SrsFlvEncoder::size_tag(data_size); | ||
| 1015 | -} | 1108 | +/** |
| 1109 | +* write h264 raw frame, maybe sps/pps/IPB-frame. | ||
| 1110 | +*/ | ||
| 1111 | +int __srs_write_h264_raw_frame(Context* context, | ||
| 1112 | + char* frame, int frame_size, u_int32_t dts, u_int32_t pts | ||
| 1113 | +) { | ||
| 1114 | + int ret = ERROR_SUCCESS; | ||
| 1016 | 1115 | ||
| 1017 | -int64_t srs_flv_tellg(srs_flv_t flv) | ||
| 1018 | -{ | ||
| 1019 | - FlvContext* context = (FlvContext*)flv; | ||
| 1020 | - return context->reader.tellg(); | ||
| 1021 | -} | 1116 | + // ignore invalid frame, |
| 1117 | + // atleast 1bytes for SPS to decode the type | ||
| 1118 | + if (frame_size < 1) { | ||
| 1119 | + return ret; | ||
| 1120 | + } | ||
| 1022 | 1121 | ||
| 1023 | -void srs_flv_lseek(srs_flv_t flv, int64_t offset) | ||
| 1024 | -{ | ||
| 1025 | - FlvContext* context = (FlvContext*)flv; | ||
| 1026 | - context->reader.lseek(offset); | ||
| 1027 | -} | 1122 | + // 5bits, 7.3.1 NAL unit syntax, |
| 1123 | + // H.264-AVC-ISO_IEC_14496-10.pdf, page 44. | ||
| 1124 | + // 7: SPS, 8: PPS, 5: I Frame, 1: P Frame | ||
| 1125 | + u_int8_t nal_unit_type = (char)frame[0] & 0x1f; | ||
| 1028 | 1126 | ||
| 1029 | -srs_flv_bool srs_flv_is_eof(int error_code) | ||
| 1030 | -{ | ||
| 1031 | - return error_code == ERROR_SYSTEM_FILE_EOF; | ||
| 1032 | -} | 1127 | + if (nal_unit_type == 7) { |
| 1128 | + // atleast 1bytes for SPS to decode the type, profile, constrain and level. | ||
| 1129 | + if (frame_size < 4) { | ||
| 1130 | + return ret; | ||
| 1131 | + } | ||
| 1033 | 1132 | ||
| 1034 | -srs_flv_bool srs_flv_is_sequence_header(char* data, int32_t size) | ||
| 1035 | -{ | ||
| 1036 | - return SrsFlvCodec::video_is_sequence_header(data, (int)size); | ||
| 1037 | -} | 1133 | + std::string sps; |
| 1134 | + sps.append(frame, frame_size); | ||
| 1038 | 1135 | ||
| 1039 | -srs_flv_bool srs_flv_is_keyframe(char* data, int32_t size) | ||
| 1040 | -{ | ||
| 1041 | - return SrsFlvCodec::video_is_keyframe(data, (int)size); | 1136 | + if (context->h264_sps == sps) { |
| 1137 | + return ERROR_H264_DUPLICATED_SPS; | ||
| 1138 | + } | ||
| 1139 | + context->h264_sps_changed = true; | ||
| 1140 | + context->h264_sps = sps; | ||
| 1141 | + | ||
| 1142 | + return __srs_write_h264_sps_pps(context, dts, pts); | ||
| 1143 | + } else if (nal_unit_type == 8) { | ||
| 1144 | + | ||
| 1145 | + std::string pps; | ||
| 1146 | + pps.append(frame, frame_size); | ||
| 1147 | + | ||
| 1148 | + if (context->h264_pps == pps) { | ||
| 1149 | + return ERROR_H264_DUPLICATED_PPS; | ||
| 1150 | + } | ||
| 1151 | + context->h264_pps_changed = true; | ||
| 1152 | + context->h264_pps = pps; | ||
| 1153 | + | ||
| 1154 | + return __srs_write_h264_sps_pps(context, dts, pts); | ||
| 1155 | + } else { | ||
| 1156 | + return __srs_write_h264_ipb_frame(context, frame, frame_size, dts, pts); | ||
| 1157 | + } | ||
| 1158 | + | ||
| 1159 | + return ret; | ||
| 1042 | } | 1160 | } |
| 1043 | 1161 | ||
| 1044 | -srs_amf0_t srs_amf0_parse(char* data, int size, int* nparsed) | ||
| 1045 | -{ | 1162 | +/** |
| 1163 | +* write h264 multiple frames, in annexb format. | ||
| 1164 | +*/ | ||
| 1165 | +int srs_h264_write_raw_frames(srs_rtmp_t rtmp, | ||
| 1166 | + char* frames, int frames_size, u_int32_t dts, u_int32_t pts | ||
| 1167 | +) { | ||
| 1046 | int ret = ERROR_SUCCESS; | 1168 | int ret = ERROR_SUCCESS; |
| 1047 | 1169 | ||
| 1048 | - srs_amf0_t amf0 = NULL; | 1170 | + srs_assert(frames != NULL); |
| 1171 | + srs_assert(frames_size > 0); | ||
| 1049 | 1172 | ||
| 1050 | - SrsStream stream; | ||
| 1051 | - if ((ret = stream.initialize(data, size)) != ERROR_SUCCESS) { | ||
| 1052 | - return amf0; | 1173 | + srs_assert(rtmp != NULL); |
| 1174 | + Context* context = (Context*)rtmp; | ||
| 1175 | + | ||
| 1176 | + if ((ret = context->h264_raw_stream.initialize(frames, frames_size)) != ERROR_SUCCESS) { | ||
| 1177 | + return ret; | ||
| 1053 | } | 1178 | } |
| 1054 | 1179 | ||
| 1055 | - SrsAmf0Any* any = NULL; | ||
| 1056 | - if ((ret = SrsAmf0Any::discovery(&stream, &any)) != ERROR_SUCCESS) { | ||
| 1057 | - return amf0; | 1180 | + // use the last error |
| 1181 | + // @see https://github.com/winlinvip/simple-rtmp-server/issues/203 | ||
| 1182 | + // @see https://github.com/winlinvip/simple-rtmp-server/issues/204 | ||
| 1183 | + int error_code_return = ret; | ||
| 1184 | + | ||
| 1185 | + // send each frame. | ||
| 1186 | + while (!context->h264_raw_stream.empty()) { | ||
| 1187 | + // each frame must prefixed by annexb format. | ||
| 1188 | + // about annexb, @see H.264-AVC-ISO_IEC_14496-10.pdf, page 211. | ||
| 1189 | + int pnb_start_code = 0; | ||
| 1190 | + if (!srs_avc_startswith_annexb(&context->h264_raw_stream, &pnb_start_code)) { | ||
| 1191 | + return ERROR_H264_API_NO_PREFIXED; | ||
| 1058 | } | 1192 | } |
| 1193 | + int start = context->h264_raw_stream.pos() + pnb_start_code; | ||
| 1059 | 1194 | ||
| 1060 | - stream.skip(-1 * stream.pos()); | ||
| 1061 | - if ((ret = any->read(&stream)) != ERROR_SUCCESS) { | ||
| 1062 | - srs_freep(any); | ||
| 1063 | - return amf0; | 1195 | + // find the last frame prefixed by annexb format. |
| 1196 | + context->h264_raw_stream.skip(pnb_start_code); | ||
| 1197 | + while (!context->h264_raw_stream.empty()) { | ||
| 1198 | + if (srs_avc_startswith_annexb(&context->h264_raw_stream, NULL)) { | ||
| 1199 | + break; | ||
| 1064 | } | 1200 | } |
| 1201 | + context->h264_raw_stream.skip(1); | ||
| 1202 | + } | ||
| 1203 | + int size = context->h264_raw_stream.pos() - start; | ||
| 1065 | 1204 | ||
| 1066 | - if (nparsed) { | ||
| 1067 | - *nparsed = stream.pos(); | 1205 | + // send out the frame. |
| 1206 | + char* frame = context->h264_raw_stream.data() + start; | ||
| 1207 | + | ||
| 1208 | + // it may be return error, but we must process all packets. | ||
| 1209 | + if ((ret = __srs_write_h264_raw_frame(context, frame, size, dts, pts)) != ERROR_SUCCESS) { | ||
| 1210 | + error_code_return = ret; | ||
| 1211 | + | ||
| 1212 | + // ignore known error, process all packets. | ||
| 1213 | + if (srs_h264_is_dvbsp_error(ret) | ||
| 1214 | + || srs_h264_is_duplicated_sps_error(ret) | ||
| 1215 | + || srs_h264_is_duplicated_pps_error(ret) | ||
| 1216 | + ) { | ||
| 1217 | + continue; | ||
| 1068 | } | 1218 | } |
| 1069 | - amf0 = (srs_amf0_t)any; | ||
| 1070 | 1219 | ||
| 1071 | - return amf0; | ||
| 1072 | -} | 1220 | + return ret; |
| 1221 | + } | ||
| 1222 | + } | ||
| 1073 | 1223 | ||
| 1074 | -srs_amf0_t srs_amf0_create_number(srs_amf0_number value) | ||
| 1075 | -{ | ||
| 1076 | - return SrsAmf0Any::number(value); | 1224 | + return error_code_return; |
| 1077 | } | 1225 | } |
| 1078 | 1226 | ||
| 1079 | -srs_amf0_t srs_amf0_create_ecma_array() | 1227 | +srs_h264_bool srs_h264_is_dvbsp_error(int error_code) |
| 1080 | { | 1228 | { |
| 1081 | - return SrsAmf0Any::ecma_array(); | 1229 | + return error_code == ERROR_H264_DROP_BEFORE_SPS_PPS; |
| 1082 | } | 1230 | } |
| 1083 | 1231 | ||
| 1084 | -srs_amf0_t srs_amf0_create_strict_array() | 1232 | +srs_h264_bool srs_h264_is_duplicated_sps_error(int error_code) |
| 1085 | { | 1233 | { |
| 1086 | - return SrsAmf0Any::strict_array(); | 1234 | + return error_code == ERROR_H264_DUPLICATED_SPS; |
| 1087 | } | 1235 | } |
| 1088 | 1236 | ||
| 1089 | -srs_amf0_t srs_amf0_create_object() | 1237 | +srs_h264_bool srs_h264_is_duplicated_pps_error(int error_code) |
| 1090 | { | 1238 | { |
| 1091 | - return SrsAmf0Any::object(); | 1239 | + return error_code == ERROR_H264_DUPLICATED_PPS; |
| 1092 | } | 1240 | } |
| 1093 | 1241 | ||
| 1094 | -void srs_amf0_free(srs_amf0_t amf0) | 1242 | +int srs_h264_startswith_annexb(char* h264_raw_data, int h264_raw_size, int* pnb_start_code) |
| 1095 | { | 1243 | { |
| 1096 | - SrsAmf0Any* any = (SrsAmf0Any*)amf0; | ||
| 1097 | - srs_freep(any); | ||
| 1098 | -} | 1244 | + SrsStream stream; |
| 1245 | + if (stream.initialize(h264_raw_data, h264_raw_size) != ERROR_SUCCESS) { | ||
| 1246 | + return false; | ||
| 1247 | + } | ||
| 1099 | 1248 | ||
| 1100 | -void srs_amf0_free_bytes(char* data) | ||
| 1101 | -{ | ||
| 1102 | - srs_freep(data); | 1249 | + return srs_avc_startswith_annexb(&stream, pnb_start_code); |
| 1103 | } | 1250 | } |
| 1104 | 1251 | ||
| 1105 | -int srs_amf0_size(srs_amf0_t amf0) | 1252 | +struct FlvContext |
| 1106 | { | 1253 | { |
| 1107 | - SrsAmf0Any* any = (SrsAmf0Any*)amf0; | ||
| 1108 | - return any->total_size(); | ||
| 1109 | -} | 1254 | + SrsFileReader reader; |
| 1255 | + SrsFileWriter writer; | ||
| 1256 | + SrsFlvEncoder enc; | ||
| 1257 | + SrsFlvDecoder dec; | ||
| 1258 | +}; | ||
| 1110 | 1259 | ||
| 1111 | -int srs_amf0_serialize(srs_amf0_t amf0, char* data, int size) | 1260 | +srs_flv_t srs_flv_open_read(const char* file) |
| 1112 | { | 1261 | { |
| 1113 | int ret = ERROR_SUCCESS; | 1262 | int ret = ERROR_SUCCESS; |
| 1114 | 1263 | ||
| 1115 | - SrsAmf0Any* any = (SrsAmf0Any*)amf0; | 1264 | + FlvContext* flv = new FlvContext(); |
| 1116 | 1265 | ||
| 1117 | - SrsStream stream; | ||
| 1118 | - if ((ret = stream.initialize(data, size)) != ERROR_SUCCESS) { | ||
| 1119 | - return ret; | 1266 | + if ((ret = flv->reader.open(file)) != ERROR_SUCCESS) { |
| 1267 | + srs_freep(flv); | ||
| 1268 | + return NULL; | ||
| 1120 | } | 1269 | } |
| 1121 | 1270 | ||
| 1122 | - if ((ret = any->write(&stream)) != ERROR_SUCCESS) { | ||
| 1123 | - return ret; | 1271 | + if ((ret = flv->dec.initialize(&flv->reader)) != ERROR_SUCCESS) { |
| 1272 | + srs_freep(flv); | ||
| 1273 | + return NULL; | ||
| 1124 | } | 1274 | } |
| 1125 | 1275 | ||
| 1126 | - return ret; | 1276 | + return flv; |
| 1127 | } | 1277 | } |
| 1128 | 1278 | ||
| 1129 | -srs_amf0_bool srs_amf0_is_string(srs_amf0_t amf0) | 1279 | +srs_flv_t srs_flv_open_write(const char* file) |
| 1130 | { | 1280 | { |
| 1131 | - SrsAmf0Any* any = (SrsAmf0Any*)amf0; | ||
| 1132 | - return any->is_string(); | ||
| 1133 | -} | 1281 | + int ret = ERROR_SUCCESS; |
| 1134 | 1282 | ||
| 1135 | -srs_amf0_bool srs_amf0_is_boolean(srs_amf0_t amf0) | ||
| 1136 | -{ | ||
| 1137 | - SrsAmf0Any* any = (SrsAmf0Any*)amf0; | ||
| 1138 | - return any->is_boolean(); | ||
| 1139 | -} | 1283 | + FlvContext* flv = new FlvContext(); |
| 1140 | 1284 | ||
| 1141 | -srs_amf0_bool srs_amf0_is_number(srs_amf0_t amf0) | ||
| 1142 | -{ | ||
| 1143 | - SrsAmf0Any* any = (SrsAmf0Any*)amf0; | ||
| 1144 | - return any->is_number(); | ||
| 1145 | -} | 1285 | + if ((ret = flv->writer.open(file)) != ERROR_SUCCESS) { |
| 1286 | + srs_freep(flv); | ||
| 1287 | + return NULL; | ||
| 1288 | + } | ||
| 1146 | 1289 | ||
| 1147 | -srs_amf0_bool srs_amf0_is_null(srs_amf0_t amf0) | ||
| 1148 | -{ | ||
| 1149 | - SrsAmf0Any* any = (SrsAmf0Any*)amf0; | ||
| 1150 | - return any->is_null(); | ||
| 1151 | -} | 1290 | + if ((ret = flv->enc.initialize(&flv->writer)) != ERROR_SUCCESS) { |
| 1291 | + srs_freep(flv); | ||
| 1292 | + return NULL; | ||
| 1293 | + } | ||
| 1152 | 1294 | ||
| 1153 | -srs_amf0_bool srs_amf0_is_object(srs_amf0_t amf0) | ||
| 1154 | -{ | ||
| 1155 | - SrsAmf0Any* any = (SrsAmf0Any*)amf0; | ||
| 1156 | - return any->is_object(); | 1295 | + return flv; |
| 1157 | } | 1296 | } |
| 1158 | 1297 | ||
| 1159 | -srs_amf0_bool srs_amf0_is_ecma_array(srs_amf0_t amf0) | 1298 | +void srs_flv_close(srs_flv_t flv) |
| 1160 | { | 1299 | { |
| 1161 | - SrsAmf0Any* any = (SrsAmf0Any*)amf0; | ||
| 1162 | - return any->is_ecma_array(); | 1300 | + FlvContext* context = (FlvContext*)flv; |
| 1301 | + srs_freep(context); | ||
| 1163 | } | 1302 | } |
| 1164 | 1303 | ||
| 1165 | -srs_amf0_bool srs_amf0_is_strict_array(srs_amf0_t amf0) | 1304 | +int srs_flv_read_header(srs_flv_t flv, char header[9]) |
| 1166 | { | 1305 | { |
| 1167 | - SrsAmf0Any* any = (SrsAmf0Any*)amf0; | ||
| 1168 | - return any->is_strict_array(); | ||
| 1169 | -} | 1306 | + int ret = ERROR_SUCCESS; |
| 1170 | 1307 | ||
| 1171 | -const char* srs_amf0_to_string(srs_amf0_t amf0) | ||
| 1172 | -{ | ||
| 1173 | - SrsAmf0Any* any = (SrsAmf0Any*)amf0; | ||
| 1174 | - return any->to_str_raw(); | ||
| 1175 | -} | 1308 | + FlvContext* context = (FlvContext*)flv; |
| 1176 | 1309 | ||
| 1177 | -srs_amf0_bool srs_amf0_to_boolean(srs_amf0_t amf0) | ||
| 1178 | -{ | ||
| 1179 | - SrsAmf0Any* any = (SrsAmf0Any*)amf0; | ||
| 1180 | - return any->to_boolean(); | ||
| 1181 | -} | 1310 | + if (!context->reader.is_open()) { |
| 1311 | + return ERROR_SYSTEM_IO_INVALID; | ||
| 1312 | + } | ||
| 1182 | 1313 | ||
| 1183 | -srs_amf0_number srs_amf0_to_number(srs_amf0_t amf0) | ||
| 1184 | -{ | ||
| 1185 | - SrsAmf0Any* any = (SrsAmf0Any*)amf0; | ||
| 1186 | - return any->to_number(); | ||
| 1187 | -} | 1314 | + if ((ret = context->dec.read_header(header)) != ERROR_SUCCESS) { |
| 1315 | + return ret; | ||
| 1316 | + } | ||
| 1188 | 1317 | ||
| 1189 | -void srs_amf0_set_number(srs_amf0_t amf0, srs_amf0_number value) | ||
| 1190 | -{ | ||
| 1191 | - SrsAmf0Any* any = (SrsAmf0Any*)amf0; | ||
| 1192 | - any->set_number(value); | 1318 | + char ts[4]; // tag size |
| 1319 | + if ((ret = context->dec.read_previous_tag_size(ts)) != ERROR_SUCCESS) { | ||
| 1320 | + return ret; | ||
| 1321 | + } | ||
| 1322 | + | ||
| 1323 | + return ret; | ||
| 1193 | } | 1324 | } |
| 1194 | 1325 | ||
| 1195 | -int srs_amf0_object_property_count(srs_amf0_t amf0) | 1326 | +int srs_flv_read_tag_header(srs_flv_t flv, char* ptype, int32_t* pdata_size, u_int32_t* ptime) |
| 1196 | { | 1327 | { |
| 1197 | - SrsAmf0Any* any = (SrsAmf0Any*)amf0; | ||
| 1198 | - srs_assert(any->is_object()); | 1328 | + int ret = ERROR_SUCCESS; |
| 1199 | 1329 | ||
| 1200 | - SrsAmf0Object* obj = (SrsAmf0Object*)amf0; | ||
| 1201 | - return obj->count(); | ||
| 1202 | -} | 1330 | + FlvContext* context = (FlvContext*)flv; |
| 1203 | 1331 | ||
| 1204 | -const char* srs_amf0_object_property_name_at(srs_amf0_t amf0, int index) | ||
| 1205 | -{ | ||
| 1206 | - SrsAmf0Any* any = (SrsAmf0Any*)amf0; | ||
| 1207 | - srs_assert(any->is_object()); | 1332 | + if (!context->reader.is_open()) { |
| 1333 | + return ERROR_SYSTEM_IO_INVALID; | ||
| 1334 | + } | ||
| 1208 | 1335 | ||
| 1209 | - SrsAmf0Object* obj = (SrsAmf0Object*)amf0; | ||
| 1210 | - return obj->key_raw_at(index); | 1336 | + if ((ret = context->dec.read_tag_header(ptype, pdata_size, ptime)) != ERROR_SUCCESS) { |
| 1337 | + return ret; | ||
| 1338 | + } | ||
| 1339 | + | ||
| 1340 | + return ret; | ||
| 1211 | } | 1341 | } |
| 1212 | 1342 | ||
| 1213 | -srs_amf0_t srs_amf0_object_property_value_at(srs_amf0_t amf0, int index) | 1343 | +int srs_flv_read_tag_data(srs_flv_t flv, char* data, int32_t size) |
| 1214 | { | 1344 | { |
| 1215 | - SrsAmf0Any* any = (SrsAmf0Any*)amf0; | ||
| 1216 | - srs_assert(any->is_object()); | 1345 | + int ret = ERROR_SUCCESS; |
| 1217 | 1346 | ||
| 1218 | - SrsAmf0Object* obj = (SrsAmf0Object*)amf0; | ||
| 1219 | - return (srs_amf0_t)obj->value_at(index); | ||
| 1220 | -} | 1347 | + FlvContext* context = (FlvContext*)flv; |
| 1221 | 1348 | ||
| 1222 | -srs_amf0_t srs_amf0_object_property(srs_amf0_t amf0, const char* name) | ||
| 1223 | -{ | ||
| 1224 | - SrsAmf0Any* any = (SrsAmf0Any*)amf0; | ||
| 1225 | - srs_assert(any->is_object()); | 1349 | + if (!context->reader.is_open()) { |
| 1350 | + return ERROR_SYSTEM_IO_INVALID; | ||
| 1351 | + } | ||
| 1226 | 1352 | ||
| 1227 | - SrsAmf0Object* obj = (SrsAmf0Object*)amf0; | ||
| 1228 | - return (srs_amf0_t)obj->get_property(name); | ||
| 1229 | -} | 1353 | + if ((ret = context->dec.read_tag_data(data, size)) != ERROR_SUCCESS) { |
| 1354 | + return ret; | ||
| 1355 | + } | ||
| 1230 | 1356 | ||
| 1231 | -void srs_amf0_object_property_set(srs_amf0_t amf0, const char* name, srs_amf0_t value) | ||
| 1232 | -{ | ||
| 1233 | - SrsAmf0Any* any = (SrsAmf0Any*)amf0; | ||
| 1234 | - srs_assert(any->is_object()); | 1357 | + char ts[4]; // tag size |
| 1358 | + if ((ret = context->dec.read_previous_tag_size(ts)) != ERROR_SUCCESS) { | ||
| 1359 | + return ret; | ||
| 1360 | + } | ||
| 1235 | 1361 | ||
| 1236 | - SrsAmf0Object* obj = (SrsAmf0Object*)amf0; | ||
| 1237 | - any = (SrsAmf0Any*)value; | ||
| 1238 | - obj->set(name, any); | 1362 | + return ret; |
| 1239 | } | 1363 | } |
| 1240 | 1364 | ||
| 1241 | -void srs_amf0_object_clear(srs_amf0_t amf0) | 1365 | +int srs_flv_write_header(srs_flv_t flv, char header[9]) |
| 1242 | { | 1366 | { |
| 1243 | - SrsAmf0Any* any = (SrsAmf0Any*)amf0; | ||
| 1244 | - srs_assert(any->is_object()); | 1367 | + int ret = ERROR_SUCCESS; |
| 1245 | 1368 | ||
| 1246 | - SrsAmf0Object* obj = (SrsAmf0Object*)amf0; | ||
| 1247 | - obj->clear(); | ||
| 1248 | -} | 1369 | + FlvContext* context = (FlvContext*)flv; |
| 1249 | 1370 | ||
| 1250 | -int srs_amf0_ecma_array_property_count(srs_amf0_t amf0) | ||
| 1251 | -{ | ||
| 1252 | - SrsAmf0Any* any = (SrsAmf0Any*)amf0; | ||
| 1253 | - srs_assert(any->is_ecma_array()); | 1371 | + if (!context->writer.is_open()) { |
| 1372 | + return ERROR_SYSTEM_IO_INVALID; | ||
| 1373 | + } | ||
| 1254 | 1374 | ||
| 1255 | - SrsAmf0EcmaArray * obj = (SrsAmf0EcmaArray*)amf0; | ||
| 1256 | - return obj->count(); | 1375 | + if ((ret = context->enc.write_header(header)) != ERROR_SUCCESS) { |
| 1376 | + return ret; | ||
| 1377 | + } | ||
| 1378 | + | ||
| 1379 | + return ret; | ||
| 1257 | } | 1380 | } |
| 1258 | 1381 | ||
| 1259 | -const char* srs_amf0_ecma_array_property_name_at(srs_amf0_t amf0, int index) | 1382 | +int srs_flv_write_tag(srs_flv_t flv, char type, int32_t time, char* data, int size) |
| 1260 | { | 1383 | { |
| 1261 | - SrsAmf0Any* any = (SrsAmf0Any*)amf0; | ||
| 1262 | - srs_assert(any->is_ecma_array()); | 1384 | + int ret = ERROR_SUCCESS; |
| 1263 | 1385 | ||
| 1264 | - SrsAmf0EcmaArray* obj = (SrsAmf0EcmaArray*)amf0; | ||
| 1265 | - return obj->key_raw_at(index); | ||
| 1266 | -} | 1386 | + FlvContext* context = (FlvContext*)flv; |
| 1267 | 1387 | ||
| 1268 | -srs_amf0_t srs_amf0_ecma_array_property_value_at(srs_amf0_t amf0, int index) | ||
| 1269 | -{ | ||
| 1270 | - SrsAmf0Any* any = (SrsAmf0Any*)amf0; | ||
| 1271 | - srs_assert(any->is_ecma_array()); | 1388 | + if (!context->writer.is_open()) { |
| 1389 | + return ERROR_SYSTEM_IO_INVALID; | ||
| 1390 | + } | ||
| 1272 | 1391 | ||
| 1273 | - SrsAmf0EcmaArray* obj = (SrsAmf0EcmaArray*)amf0; | ||
| 1274 | - return (srs_amf0_t)obj->value_at(index); | 1392 | + if (type == SRS_RTMP_TYPE_AUDIO) { |
| 1393 | + return context->enc.write_audio(time, data, size); | ||
| 1394 | + } else if (type == SRS_RTMP_TYPE_VIDEO) { | ||
| 1395 | + return context->enc.write_video(time, data, size); | ||
| 1396 | + } else { | ||
| 1397 | + return context->enc.write_metadata(data, size); | ||
| 1398 | + } | ||
| 1399 | + | ||
| 1400 | + return ret; | ||
| 1275 | } | 1401 | } |
| 1276 | 1402 | ||
| 1277 | -srs_amf0_t srs_amf0_ecma_array_property(srs_amf0_t amf0, const char* name) | 1403 | +int srs_flv_size_tag(int data_size) |
| 1278 | { | 1404 | { |
| 1279 | - SrsAmf0Any* any = (SrsAmf0Any*)amf0; | ||
| 1280 | - srs_assert(any->is_ecma_array()); | ||
| 1281 | - | ||
| 1282 | - SrsAmf0EcmaArray* obj = (SrsAmf0EcmaArray*)amf0; | ||
| 1283 | - return (srs_amf0_t)obj->get_property(name); | 1405 | + return SrsFlvEncoder::size_tag(data_size); |
| 1284 | } | 1406 | } |
| 1285 | 1407 | ||
| 1286 | -void srs_amf0_ecma_array_property_set(srs_amf0_t amf0, const char* name, srs_amf0_t value) | 1408 | +int64_t srs_flv_tellg(srs_flv_t flv) |
| 1287 | { | 1409 | { |
| 1288 | - SrsAmf0Any* any = (SrsAmf0Any*)amf0; | ||
| 1289 | - srs_assert(any->is_ecma_array()); | ||
| 1290 | - | ||
| 1291 | - SrsAmf0EcmaArray* obj = (SrsAmf0EcmaArray*)amf0; | ||
| 1292 | - any = (SrsAmf0Any*)value; | ||
| 1293 | - obj->set(name, any); | 1410 | + FlvContext* context = (FlvContext*)flv; |
| 1411 | + return context->reader.tellg(); | ||
| 1294 | } | 1412 | } |
| 1295 | 1413 | ||
| 1296 | -int srs_amf0_strict_array_property_count(srs_amf0_t amf0) | 1414 | +void srs_flv_lseek(srs_flv_t flv, int64_t offset) |
| 1297 | { | 1415 | { |
| 1298 | - SrsAmf0Any* any = (SrsAmf0Any*)amf0; | ||
| 1299 | - srs_assert(any->is_strict_array()); | ||
| 1300 | - | ||
| 1301 | - SrsAmf0StrictArray * obj = (SrsAmf0StrictArray*)amf0; | ||
| 1302 | - return obj->count(); | 1416 | + FlvContext* context = (FlvContext*)flv; |
| 1417 | + context->reader.lseek(offset); | ||
| 1303 | } | 1418 | } |
| 1304 | 1419 | ||
| 1305 | -srs_amf0_t srs_amf0_strict_array_property_at(srs_amf0_t amf0, int index) | 1420 | +srs_flv_bool srs_flv_is_eof(int error_code) |
| 1306 | { | 1421 | { |
| 1307 | - SrsAmf0Any* any = (SrsAmf0Any*)amf0; | ||
| 1308 | - srs_assert(any->is_strict_array()); | ||
| 1309 | - | ||
| 1310 | - SrsAmf0StrictArray* obj = (SrsAmf0StrictArray*)amf0; | ||
| 1311 | - return (srs_amf0_t)obj->at(index); | 1422 | + return error_code == ERROR_SYSTEM_FILE_EOF; |
| 1312 | } | 1423 | } |
| 1313 | 1424 | ||
| 1314 | -void srs_amf0_strict_array_append(srs_amf0_t amf0, srs_amf0_t value) | 1425 | +srs_flv_bool srs_flv_is_sequence_header(char* data, int32_t size) |
| 1315 | { | 1426 | { |
| 1316 | - SrsAmf0Any* any = (SrsAmf0Any*)amf0; | ||
| 1317 | - srs_assert(any->is_strict_array()); | 1427 | + return SrsFlvCodec::video_is_sequence_header(data, (int)size); |
| 1428 | +} | ||
| 1318 | 1429 | ||
| 1319 | - SrsAmf0StrictArray* obj = (SrsAmf0StrictArray*)amf0; | ||
| 1320 | - any = (SrsAmf0Any*)value; | ||
| 1321 | - obj->append(any); | 1430 | +srs_flv_bool srs_flv_is_keyframe(char* data, int32_t size) |
| 1431 | +{ | ||
| 1432 | + return SrsFlvCodec::video_is_keyframe(data, (int)size); | ||
| 1322 | } | 1433 | } |
| 1323 | 1434 | ||
| 1324 | -/** | ||
| 1325 | -* write audio raw frame to SRS. | ||
| 1326 | -*/ | ||
| 1327 | -int srs_audio_write_raw_frame(srs_rtmp_t rtmp, | ||
| 1328 | - char sound_format, char sound_rate, char sound_size, char sound_type, | ||
| 1329 | - char aac_packet_type, char* frame, int frame_size, u_int32_t timestamp | ||
| 1330 | -) { | ||
| 1331 | - Context* context = (Context*)rtmp; | ||
| 1332 | - srs_assert(context); | 1435 | +srs_amf0_t srs_amf0_parse(char* data, int size, int* nparsed) |
| 1436 | +{ | ||
| 1437 | + int ret = ERROR_SUCCESS; | ||
| 1333 | 1438 | ||
| 1334 | - // TODO: FIXME: for aac, must send the sequence header first. | 1439 | + srs_amf0_t amf0 = NULL; |
| 1335 | 1440 | ||
| 1336 | - // for audio frame, there is 1 or 2 bytes header: | ||
| 1337 | - // 1bytes, SoundFormat|SoundRate|SoundSize|SoundType | ||
| 1338 | - // 1bytes, AACPacketType for SoundFormat == 10 | ||
| 1339 | - int size = frame_size + 1; | ||
| 1340 | - if (aac_packet_type == SrsCodecAudioAAC) { | ||
| 1341 | - size += 1; | 1441 | + SrsStream stream; |
| 1442 | + if ((ret = stream.initialize(data, size)) != ERROR_SUCCESS) { | ||
| 1443 | + return amf0; | ||
| 1342 | } | 1444 | } |
| 1343 | - char* data = new char[size]; | ||
| 1344 | - char* p = data; | ||
| 1345 | - | ||
| 1346 | - u_int8_t audio_header = sound_type & 0x01; | ||
| 1347 | - audio_header |= (sound_size << 1) & 0x02; | ||
| 1348 | - audio_header |= (sound_rate << 2) & 0x0c; | ||
| 1349 | - audio_header |= (sound_format << 4) & 0xf0; | ||
| 1350 | 1445 | ||
| 1351 | - *p++ = audio_header; | 1446 | + SrsAmf0Any* any = NULL; |
| 1447 | + if ((ret = SrsAmf0Any::discovery(&stream, &any)) != ERROR_SUCCESS) { | ||
| 1448 | + return amf0; | ||
| 1449 | + } | ||
| 1352 | 1450 | ||
| 1353 | - if (aac_packet_type == SrsCodecAudioAAC) { | ||
| 1354 | - *p++ = aac_packet_type; | 1451 | + stream.skip(-1 * stream.pos()); |
| 1452 | + if ((ret = any->read(&stream)) != ERROR_SUCCESS) { | ||
| 1453 | + srs_freep(any); | ||
| 1454 | + return amf0; | ||
| 1355 | } | 1455 | } |
| 1356 | 1456 | ||
| 1357 | - memcpy(p, frame, frame_size); | 1457 | + if (nparsed) { |
| 1458 | + *nparsed = stream.pos(); | ||
| 1459 | + } | ||
| 1460 | + amf0 = (srs_amf0_t)any; | ||
| 1358 | 1461 | ||
| 1359 | - return srs_rtmp_write_packet(context, SRS_RTMP_TYPE_AUDIO, timestamp, data, size); | 1462 | + return amf0; |
| 1360 | } | 1463 | } |
| 1361 | 1464 | ||
| 1362 | -/** | ||
| 1363 | -* write h264 packet, with rtmp header. | ||
| 1364 | -* @param frame_type, SrsCodecVideoAVCFrameKeyFrame or SrsCodecVideoAVCFrameInterFrame. | ||
| 1365 | -* @param avc_packet_type, SrsCodecVideoAVCTypeSequenceHeader or SrsCodecVideoAVCTypeNALU. | ||
| 1366 | -* @param h264_raw_data the h.264 raw data, user must free it. | ||
| 1367 | -*/ | ||
| 1368 | -int __srs_write_h264_packet(Context* context, | ||
| 1369 | - int8_t frame_type, int8_t avc_packet_type, | ||
| 1370 | - char* h264_raw_data, int h264_raw_size, u_int32_t dts, u_int32_t pts | ||
| 1371 | -) { | ||
| 1372 | - // the timestamp in rtmp message header is dts. | ||
| 1373 | - u_int32_t timestamp = dts; | 1465 | +srs_amf0_t srs_amf0_create_number(srs_amf0_number value) |
| 1466 | +{ | ||
| 1467 | + return SrsAmf0Any::number(value); | ||
| 1468 | +} | ||
| 1374 | 1469 | ||
| 1375 | - // for h264 in RTMP video payload, there is 5bytes header: | ||
| 1376 | - // 1bytes, FrameType | CodecID | ||
| 1377 | - // 1bytes, AVCPacketType | ||
| 1378 | - // 3bytes, CompositionTime, the cts. | ||
| 1379 | - // @see: E.4.3 Video Tags, video_file_format_spec_v10_1.pdf, page 78 | ||
| 1380 | - int size = h264_raw_size + 5; | ||
| 1381 | - char* data = new char[size]; | ||
| 1382 | - char* p = data; | 1470 | +srs_amf0_t srs_amf0_create_ecma_array() |
| 1471 | +{ | ||
| 1472 | + return SrsAmf0Any::ecma_array(); | ||
| 1473 | +} | ||
| 1383 | 1474 | ||
| 1384 | - // @see: E.4.3 Video Tags, video_file_format_spec_v10_1.pdf, page 78 | ||
| 1385 | - // Frame Type, Type of video frame. | ||
| 1386 | - // CodecID, Codec Identifier. | ||
| 1387 | - // set the rtmp header | ||
| 1388 | - *p++ = (frame_type << 4) | SrsCodecVideoAVC; | 1475 | +srs_amf0_t srs_amf0_create_strict_array() |
| 1476 | +{ | ||
| 1477 | + return SrsAmf0Any::strict_array(); | ||
| 1478 | +} | ||
| 1389 | 1479 | ||
| 1390 | - // AVCPacketType | ||
| 1391 | - *p++ = avc_packet_type; | 1480 | +srs_amf0_t srs_amf0_create_object() |
| 1481 | +{ | ||
| 1482 | + return SrsAmf0Any::object(); | ||
| 1483 | +} | ||
| 1392 | 1484 | ||
| 1393 | - // CompositionTime | ||
| 1394 | - // pts = dts + cts, or | ||
| 1395 | - // cts = pts - dts. | ||
| 1396 | - // where cts is the header in rtmp video packet payload header. | ||
| 1397 | - u_int32_t cts = pts - dts; | ||
| 1398 | - char* pp = (char*)&cts; | ||
| 1399 | - *p++ = pp[2]; | ||
| 1400 | - *p++ = pp[1]; | ||
| 1401 | - *p++ = pp[0]; | 1485 | +void srs_amf0_free(srs_amf0_t amf0) |
| 1486 | +{ | ||
| 1487 | + SrsAmf0Any* any = (SrsAmf0Any*)amf0; | ||
| 1488 | + srs_freep(any); | ||
| 1489 | +} | ||
| 1402 | 1490 | ||
| 1403 | - // h.264 raw data. | ||
| 1404 | - memcpy(p, h264_raw_data, h264_raw_size); | 1491 | +void srs_amf0_free_bytes(char* data) |
| 1492 | +{ | ||
| 1493 | + srs_freep(data); | ||
| 1494 | +} | ||
| 1405 | 1495 | ||
| 1406 | - return srs_rtmp_write_packet(context, SRS_RTMP_TYPE_VIDEO, timestamp, data, size); | 1496 | +int srs_amf0_size(srs_amf0_t amf0) |
| 1497 | +{ | ||
| 1498 | + SrsAmf0Any* any = (SrsAmf0Any*)amf0; | ||
| 1499 | + return any->total_size(); | ||
| 1407 | } | 1500 | } |
| 1408 | 1501 | ||
| 1409 | -/** | ||
| 1410 | -* write the h264 sps/pps in context over RTMP. | ||
| 1411 | -*/ | ||
| 1412 | -int __srs_write_h264_sps_pps(Context* context, u_int32_t dts, u_int32_t pts) | 1502 | +int srs_amf0_serialize(srs_amf0_t amf0, char* data, int size) |
| 1413 | { | 1503 | { |
| 1414 | int ret = ERROR_SUCCESS; | 1504 | int ret = ERROR_SUCCESS; |
| 1415 | 1505 | ||
| 1416 | - // only send when both sps and pps changed. | ||
| 1417 | - if (!context->h264_sps_changed || !context->h264_pps_changed) { | ||
| 1418 | - return ret; | ||
| 1419 | - } | ||
| 1420 | - | ||
| 1421 | - // 5bytes sps/pps header: | ||
| 1422 | - // configurationVersion, AVCProfileIndication, profile_compatibility, | ||
| 1423 | - // AVCLevelIndication, lengthSizeMinusOne | ||
| 1424 | - // 3bytes size of sps: | ||
| 1425 | - // numOfSequenceParameterSets, sequenceParameterSetLength(2B) | ||
| 1426 | - // Nbytes of sps. | ||
| 1427 | - // sequenceParameterSetNALUnit | ||
| 1428 | - // 3bytes size of pps: | ||
| 1429 | - // numOfPictureParameterSets, pictureParameterSetLength | ||
| 1430 | - // Nbytes of pps: | ||
| 1431 | - // pictureParameterSetNALUnit | ||
| 1432 | - int nb_packet = 5 | ||
| 1433 | - + 3 + (int)context->h264_sps.length() | ||
| 1434 | - + 3 + (int)context->h264_pps.length(); | ||
| 1435 | - char* packet = new char[nb_packet]; | ||
| 1436 | - SrsAutoFree(char, packet); | 1506 | + SrsAmf0Any* any = (SrsAmf0Any*)amf0; |
| 1437 | 1507 | ||
| 1438 | - // use stream to generate the h264 packet. | ||
| 1439 | SrsStream stream; | 1508 | SrsStream stream; |
| 1440 | - if ((ret = stream.initialize(packet, nb_packet)) != ERROR_SUCCESS) { | 1509 | + if ((ret = stream.initialize(data, size)) != ERROR_SUCCESS) { |
| 1441 | return ret; | 1510 | return ret; |
| 1442 | } | 1511 | } |
| 1443 | 1512 | ||
| 1444 | - // decode the SPS: | ||
| 1445 | - // @see: 7.3.2.1.1, H.264-AVC-ISO_IEC_14496-10-2012.pdf, page 62 | ||
| 1446 | - if (true) { | ||
| 1447 | - srs_assert((int)context->h264_sps.length() >= 4); | ||
| 1448 | - char* frame = (char*)context->h264_sps.data(); | ||
| 1449 | - | ||
| 1450 | - // @see: Annex A Profiles and levels, H.264-AVC-ISO_IEC_14496-10.pdf, page 205 | ||
| 1451 | - // Baseline profile profile_idc is 66(0x42). | ||
| 1452 | - // Main profile profile_idc is 77(0x4d). | ||
| 1453 | - // Extended profile profile_idc is 88(0x58). | ||
| 1454 | - u_int8_t profile_idc = frame[1]; | ||
| 1455 | - //u_int8_t constraint_set = frame[2]; | ||
| 1456 | - u_int8_t level_idc = frame[3]; | ||
| 1457 | - | ||
| 1458 | - // generate the sps/pps header | ||
| 1459 | - // 5.3.4.2.1 Syntax, H.264-AVC-ISO_IEC_14496-15.pdf, page 16 | ||
| 1460 | - // configurationVersion | ||
| 1461 | - stream.write_1bytes(0x01); | ||
| 1462 | - // AVCProfileIndication | ||
| 1463 | - stream.write_1bytes(profile_idc); | ||
| 1464 | - // profile_compatibility | ||
| 1465 | - stream.write_1bytes(0x00); | ||
| 1466 | - // AVCLevelIndication | ||
| 1467 | - stream.write_1bytes(level_idc); | ||
| 1468 | - // lengthSizeMinusOne, or NAL_unit_length, always use 4bytes size, | ||
| 1469 | - // so we always set it to 0x03. | ||
| 1470 | - stream.write_1bytes(0x03); | ||
| 1471 | - } | ||
| 1472 | - | ||
| 1473 | - // sps | ||
| 1474 | - if (true) { | ||
| 1475 | - // 5.3.4.2.1 Syntax, H.264-AVC-ISO_IEC_14496-15.pdf, page 16 | ||
| 1476 | - // numOfSequenceParameterSets, always 1 | ||
| 1477 | - stream.write_1bytes(0x01); | ||
| 1478 | - // sequenceParameterSetLength | ||
| 1479 | - stream.write_2bytes(context->h264_sps.length()); | ||
| 1480 | - // sequenceParameterSetNALUnit | ||
| 1481 | - stream.write_string(context->h264_sps); | ||
| 1482 | - } | ||
| 1483 | - | ||
| 1484 | - // pps | ||
| 1485 | - if (true) { | ||
| 1486 | - // 5.3.4.2.1 Syntax, H.264-AVC-ISO_IEC_14496-15.pdf, page 16 | ||
| 1487 | - // numOfPictureParameterSets, always 1 | ||
| 1488 | - stream.write_1bytes(0x01); | ||
| 1489 | - // pictureParameterSetLength | ||
| 1490 | - stream.write_2bytes(context->h264_pps.length()); | ||
| 1491 | - // pictureParameterSetNALUnit | ||
| 1492 | - stream.write_string(context->h264_pps); | 1513 | + if ((ret = any->write(&stream)) != ERROR_SUCCESS) { |
| 1514 | + return ret; | ||
| 1493 | } | 1515 | } |
| 1494 | 1516 | ||
| 1495 | - // reset sps and pps. | ||
| 1496 | - context->h264_sps_changed = false; | ||
| 1497 | - context->h264_pps_changed = false; | ||
| 1498 | - context->h264_sps_pps_sent = true; | ||
| 1499 | - | ||
| 1500 | - // TODO: FIXME: for more profile. | ||
| 1501 | - // 5.3.4.2.1 Syntax, H.264-AVC-ISO_IEC_14496-15.pdf, page 16 | ||
| 1502 | - // profile_idc == 100 || profile_idc == 110 || profile_idc == 122 || profile_idc == 144 | ||
| 1503 | - | ||
| 1504 | - // send out h264 packet. | ||
| 1505 | - int8_t frame_type = SrsCodecVideoAVCFrameKeyFrame; | ||
| 1506 | - int8_t avc_packet_type = SrsCodecVideoAVCTypeSequenceHeader; | ||
| 1507 | - return __srs_write_h264_packet( | ||
| 1508 | - context, frame_type, avc_packet_type, | ||
| 1509 | - packet, nb_packet, dts, pts | ||
| 1510 | - ); | 1517 | + return ret; |
| 1511 | } | 1518 | } |
| 1512 | 1519 | ||
| 1513 | -/** | ||
| 1514 | -* write h264 IPB-frame. | ||
| 1515 | -*/ | ||
| 1516 | -int __srs_write_h264_ipb_frame(Context* context, | ||
| 1517 | - char* data, int size, u_int32_t dts, u_int32_t pts | ||
| 1518 | -) { | ||
| 1519 | - int ret = ERROR_SUCCESS; | ||
| 1520 | - | ||
| 1521 | - // when sps or pps not sent, ignore the packet. | ||
| 1522 | - // @see https://github.com/winlinvip/simple-rtmp-server/issues/203 | ||
| 1523 | - if (!context->h264_sps_pps_sent) { | ||
| 1524 | - return ERROR_H264_DROP_BEFORE_SPS_PPS; | ||
| 1525 | - } | 1520 | +srs_amf0_bool srs_amf0_is_string(srs_amf0_t amf0) |
| 1521 | +{ | ||
| 1522 | + SrsAmf0Any* any = (SrsAmf0Any*)amf0; | ||
| 1523 | + return any->is_string(); | ||
| 1524 | +} | ||
| 1526 | 1525 | ||
| 1527 | - // 5bits, 7.3.1 NAL unit syntax, | ||
| 1528 | - // H.264-AVC-ISO_IEC_14496-10.pdf, page 44. | ||
| 1529 | - // 7: SPS, 8: PPS, 5: I Frame, 1: P Frame | ||
| 1530 | - u_int8_t nal_unit_type = (char)data[0] & 0x1f; | 1526 | +srs_amf0_bool srs_amf0_is_boolean(srs_amf0_t amf0) |
| 1527 | +{ | ||
| 1528 | + SrsAmf0Any* any = (SrsAmf0Any*)amf0; | ||
| 1529 | + return any->is_boolean(); | ||
| 1530 | +} | ||
| 1531 | 1531 | ||
| 1532 | - // 4bytes size of nalu: | ||
| 1533 | - // NALUnitLength | ||
| 1534 | - // Nbytes of nalu. | ||
| 1535 | - // NALUnit | ||
| 1536 | - int nb_packet = 4 + size; | ||
| 1537 | - char* packet = new char[nb_packet]; | ||
| 1538 | - SrsAutoFree(char, packet); | 1532 | +srs_amf0_bool srs_amf0_is_number(srs_amf0_t amf0) |
| 1533 | +{ | ||
| 1534 | + SrsAmf0Any* any = (SrsAmf0Any*)amf0; | ||
| 1535 | + return any->is_number(); | ||
| 1536 | +} | ||
| 1539 | 1537 | ||
| 1540 | - // use stream to generate the h264 packet. | ||
| 1541 | - SrsStream stream; | ||
| 1542 | - if ((ret = stream.initialize(packet, nb_packet)) != ERROR_SUCCESS) { | ||
| 1543 | - return ret; | ||
| 1544 | - } | 1538 | +srs_amf0_bool srs_amf0_is_null(srs_amf0_t amf0) |
| 1539 | +{ | ||
| 1540 | + SrsAmf0Any* any = (SrsAmf0Any*)amf0; | ||
| 1541 | + return any->is_null(); | ||
| 1542 | +} | ||
| 1545 | 1543 | ||
| 1546 | - // 5.3.4.2.1 Syntax, H.264-AVC-ISO_IEC_14496-15.pdf, page 16 | ||
| 1547 | - // lengthSizeMinusOne, or NAL_unit_length, always use 4bytes size | ||
| 1548 | - u_int32_t NAL_unit_length = size; | 1544 | +srs_amf0_bool srs_amf0_is_object(srs_amf0_t amf0) |
| 1545 | +{ | ||
| 1546 | + SrsAmf0Any* any = (SrsAmf0Any*)amf0; | ||
| 1547 | + return any->is_object(); | ||
| 1548 | +} | ||
| 1549 | 1549 | ||
| 1550 | - // mux the avc NALU in "ISO Base Media File Format" | ||
| 1551 | - // from H.264-AVC-ISO_IEC_14496-15.pdf, page 20 | ||
| 1552 | - // NALUnitLength | ||
| 1553 | - stream.write_4bytes(NAL_unit_length); | ||
| 1554 | - // NALUnit | ||
| 1555 | - stream.write_bytes(data, size); | 1550 | +srs_amf0_bool srs_amf0_is_ecma_array(srs_amf0_t amf0) |
| 1551 | +{ | ||
| 1552 | + SrsAmf0Any* any = (SrsAmf0Any*)amf0; | ||
| 1553 | + return any->is_ecma_array(); | ||
| 1554 | +} | ||
| 1556 | 1555 | ||
| 1557 | - // send out h264 packet. | ||
| 1558 | - int8_t frame_type = SrsCodecVideoAVCFrameInterFrame; | ||
| 1559 | - if (nal_unit_type != 1) { | ||
| 1560 | - frame_type = SrsCodecVideoAVCFrameKeyFrame; | ||
| 1561 | - } | ||
| 1562 | - int8_t avc_packet_type = SrsCodecVideoAVCTypeNALU; | ||
| 1563 | - return __srs_write_h264_packet( | ||
| 1564 | - context, frame_type, avc_packet_type, | ||
| 1565 | - packet, nb_packet, dts, pts | ||
| 1566 | - ); | 1556 | +srs_amf0_bool srs_amf0_is_strict_array(srs_amf0_t amf0) |
| 1557 | +{ | ||
| 1558 | + SrsAmf0Any* any = (SrsAmf0Any*)amf0; | ||
| 1559 | + return any->is_strict_array(); | ||
| 1560 | +} | ||
| 1567 | 1561 | ||
| 1568 | - return ret; | 1562 | +const char* srs_amf0_to_string(srs_amf0_t amf0) |
| 1563 | +{ | ||
| 1564 | + SrsAmf0Any* any = (SrsAmf0Any*)amf0; | ||
| 1565 | + return any->to_str_raw(); | ||
| 1569 | } | 1566 | } |
| 1570 | 1567 | ||
| 1571 | -/** | ||
| 1572 | -* write h264 raw frame, maybe sps/pps/IPB-frame. | ||
| 1573 | -*/ | ||
| 1574 | -int __srs_write_h264_raw_frame(Context* context, | ||
| 1575 | - char* frame, int frame_size, u_int32_t dts, u_int32_t pts | ||
| 1576 | -) { | ||
| 1577 | - int ret = ERROR_SUCCESS; | 1568 | +srs_amf0_bool srs_amf0_to_boolean(srs_amf0_t amf0) |
| 1569 | +{ | ||
| 1570 | + SrsAmf0Any* any = (SrsAmf0Any*)amf0; | ||
| 1571 | + return any->to_boolean(); | ||
| 1572 | +} | ||
| 1578 | 1573 | ||
| 1579 | - // ignore invalid frame, | ||
| 1580 | - // atleast 1bytes for SPS to decode the type | ||
| 1581 | - if (frame_size < 1) { | ||
| 1582 | - return ret; | ||
| 1583 | - } | 1574 | +srs_amf0_number srs_amf0_to_number(srs_amf0_t amf0) |
| 1575 | +{ | ||
| 1576 | + SrsAmf0Any* any = (SrsAmf0Any*)amf0; | ||
| 1577 | + return any->to_number(); | ||
| 1578 | +} | ||
| 1584 | 1579 | ||
| 1585 | - // 5bits, 7.3.1 NAL unit syntax, | ||
| 1586 | - // H.264-AVC-ISO_IEC_14496-10.pdf, page 44. | ||
| 1587 | - // 7: SPS, 8: PPS, 5: I Frame, 1: P Frame | ||
| 1588 | - u_int8_t nal_unit_type = (char)frame[0] & 0x1f; | 1580 | +void srs_amf0_set_number(srs_amf0_t amf0, srs_amf0_number value) |
| 1581 | +{ | ||
| 1582 | + SrsAmf0Any* any = (SrsAmf0Any*)amf0; | ||
| 1583 | + any->set_number(value); | ||
| 1584 | +} | ||
| 1589 | 1585 | ||
| 1590 | - if (nal_unit_type == 7) { | ||
| 1591 | - // atleast 1bytes for SPS to decode the type, profile, constrain and level. | ||
| 1592 | - if (frame_size < 4) { | ||
| 1593 | - return ret; | ||
| 1594 | - } | 1586 | +int srs_amf0_object_property_count(srs_amf0_t amf0) |
| 1587 | +{ | ||
| 1588 | + SrsAmf0Any* any = (SrsAmf0Any*)amf0; | ||
| 1589 | + srs_assert(any->is_object()); | ||
| 1595 | 1590 | ||
| 1596 | - std::string sps; | ||
| 1597 | - sps.append(frame, frame_size); | 1591 | + SrsAmf0Object* obj = (SrsAmf0Object*)amf0; |
| 1592 | + return obj->count(); | ||
| 1593 | +} | ||
| 1598 | 1594 | ||
| 1599 | - if (context->h264_sps == sps) { | ||
| 1600 | - return ERROR_H264_DUPLICATED_SPS; | ||
| 1601 | - } | ||
| 1602 | - context->h264_sps_changed = true; | ||
| 1603 | - context->h264_sps = sps; | 1595 | +const char* srs_amf0_object_property_name_at(srs_amf0_t amf0, int index) |
| 1596 | +{ | ||
| 1597 | + SrsAmf0Any* any = (SrsAmf0Any*)amf0; | ||
| 1598 | + srs_assert(any->is_object()); | ||
| 1604 | 1599 | ||
| 1605 | - return __srs_write_h264_sps_pps(context, dts, pts); | ||
| 1606 | - } else if (nal_unit_type == 8) { | 1600 | + SrsAmf0Object* obj = (SrsAmf0Object*)amf0; |
| 1601 | + return obj->key_raw_at(index); | ||
| 1602 | +} | ||
| 1607 | 1603 | ||
| 1608 | - std::string pps; | ||
| 1609 | - pps.append(frame, frame_size); | 1604 | +srs_amf0_t srs_amf0_object_property_value_at(srs_amf0_t amf0, int index) |
| 1605 | +{ | ||
| 1606 | + SrsAmf0Any* any = (SrsAmf0Any*)amf0; | ||
| 1607 | + srs_assert(any->is_object()); | ||
| 1610 | 1608 | ||
| 1611 | - if (context->h264_pps == pps) { | ||
| 1612 | - return ERROR_H264_DUPLICATED_PPS; | ||
| 1613 | - } | ||
| 1614 | - context->h264_pps_changed = true; | ||
| 1615 | - context->h264_pps = pps; | 1609 | + SrsAmf0Object* obj = (SrsAmf0Object*)amf0; |
| 1610 | + return (srs_amf0_t)obj->value_at(index); | ||
| 1611 | +} | ||
| 1616 | 1612 | ||
| 1617 | - return __srs_write_h264_sps_pps(context, dts, pts); | ||
| 1618 | - } else { | ||
| 1619 | - return __srs_write_h264_ipb_frame(context, frame, frame_size, dts, pts); | ||
| 1620 | - } | 1613 | +srs_amf0_t srs_amf0_object_property(srs_amf0_t amf0, const char* name) |
| 1614 | +{ | ||
| 1615 | + SrsAmf0Any* any = (SrsAmf0Any*)amf0; | ||
| 1616 | + srs_assert(any->is_object()); | ||
| 1621 | 1617 | ||
| 1622 | - return ret; | 1618 | + SrsAmf0Object* obj = (SrsAmf0Object*)amf0; |
| 1619 | + return (srs_amf0_t)obj->get_property(name); | ||
| 1623 | } | 1620 | } |
| 1624 | 1621 | ||
| 1625 | -/** | ||
| 1626 | -* write h264 multiple frames, in annexb format. | ||
| 1627 | -*/ | ||
| 1628 | -int srs_h264_write_raw_frames(srs_rtmp_t rtmp, | ||
| 1629 | - char* frames, int frames_size, u_int32_t dts, u_int32_t pts | ||
| 1630 | -) { | ||
| 1631 | - int ret = ERROR_SUCCESS; | 1622 | +void srs_amf0_object_property_set(srs_amf0_t amf0, const char* name, srs_amf0_t value) |
| 1623 | +{ | ||
| 1624 | + SrsAmf0Any* any = (SrsAmf0Any*)amf0; | ||
| 1625 | + srs_assert(any->is_object()); | ||
| 1632 | 1626 | ||
| 1633 | - srs_assert(frames != NULL); | ||
| 1634 | - srs_assert(frames_size > 0); | 1627 | + SrsAmf0Object* obj = (SrsAmf0Object*)amf0; |
| 1628 | + any = (SrsAmf0Any*)value; | ||
| 1629 | + obj->set(name, any); | ||
| 1630 | +} | ||
| 1635 | 1631 | ||
| 1636 | - srs_assert(rtmp != NULL); | ||
| 1637 | - Context* context = (Context*)rtmp; | 1632 | +void srs_amf0_object_clear(srs_amf0_t amf0) |
| 1633 | +{ | ||
| 1634 | + SrsAmf0Any* any = (SrsAmf0Any*)amf0; | ||
| 1635 | + srs_assert(any->is_object()); | ||
| 1638 | 1636 | ||
| 1639 | - if ((ret = context->h264_raw_stream.initialize(frames, frames_size)) != ERROR_SUCCESS) { | ||
| 1640 | - return ret; | ||
| 1641 | - } | 1637 | + SrsAmf0Object* obj = (SrsAmf0Object*)amf0; |
| 1638 | + obj->clear(); | ||
| 1639 | +} | ||
| 1642 | 1640 | ||
| 1643 | - // use the last error | ||
| 1644 | - // @see https://github.com/winlinvip/simple-rtmp-server/issues/203 | ||
| 1645 | - // @see https://github.com/winlinvip/simple-rtmp-server/issues/204 | ||
| 1646 | - int error_code_return = ret; | 1641 | +int srs_amf0_ecma_array_property_count(srs_amf0_t amf0) |
| 1642 | +{ | ||
| 1643 | + SrsAmf0Any* any = (SrsAmf0Any*)amf0; | ||
| 1644 | + srs_assert(any->is_ecma_array()); | ||
| 1647 | 1645 | ||
| 1648 | - // send each frame. | ||
| 1649 | - while (!context->h264_raw_stream.empty()) { | ||
| 1650 | - // each frame must prefixed by annexb format. | ||
| 1651 | - // about annexb, @see H.264-AVC-ISO_IEC_14496-10.pdf, page 211. | ||
| 1652 | - int pnb_start_code = 0; | ||
| 1653 | - if (!srs_avc_startswith_annexb(&context->h264_raw_stream, &pnb_start_code)) { | ||
| 1654 | - return ERROR_H264_API_NO_PREFIXED; | ||
| 1655 | - } | ||
| 1656 | - int start = context->h264_raw_stream.pos() + pnb_start_code; | 1646 | + SrsAmf0EcmaArray * obj = (SrsAmf0EcmaArray*)amf0; |
| 1647 | + return obj->count(); | ||
| 1648 | +} | ||
| 1657 | 1649 | ||
| 1658 | - // find the last frame prefixed by annexb format. | ||
| 1659 | - context->h264_raw_stream.skip(pnb_start_code); | ||
| 1660 | - while (!context->h264_raw_stream.empty()) { | ||
| 1661 | - if (srs_avc_startswith_annexb(&context->h264_raw_stream, NULL)) { | ||
| 1662 | - break; | ||
| 1663 | - } | ||
| 1664 | - context->h264_raw_stream.skip(1); | ||
| 1665 | - } | ||
| 1666 | - int size = context->h264_raw_stream.pos() - start; | 1650 | +const char* srs_amf0_ecma_array_property_name_at(srs_amf0_t amf0, int index) |
| 1651 | +{ | ||
| 1652 | + SrsAmf0Any* any = (SrsAmf0Any*)amf0; | ||
| 1653 | + srs_assert(any->is_ecma_array()); | ||
| 1667 | 1654 | ||
| 1668 | - // send out the frame. | ||
| 1669 | - char* frame = context->h264_raw_stream.data() + start; | 1655 | + SrsAmf0EcmaArray* obj = (SrsAmf0EcmaArray*)amf0; |
| 1656 | + return obj->key_raw_at(index); | ||
| 1657 | +} | ||
| 1670 | 1658 | ||
| 1671 | - // it may be return error, but we must process all packets. | ||
| 1672 | - if ((ret = __srs_write_h264_raw_frame(context, frame, size, dts, pts)) != ERROR_SUCCESS) { | ||
| 1673 | - error_code_return = ret; | 1659 | +srs_amf0_t srs_amf0_ecma_array_property_value_at(srs_amf0_t amf0, int index) |
| 1660 | +{ | ||
| 1661 | + SrsAmf0Any* any = (SrsAmf0Any*)amf0; | ||
| 1662 | + srs_assert(any->is_ecma_array()); | ||
| 1674 | 1663 | ||
| 1675 | - // ignore known error, process all packets. | ||
| 1676 | - if (srs_h264_is_dvbsp_error(ret) | ||
| 1677 | - || srs_h264_is_duplicated_sps_error(ret) | ||
| 1678 | - || srs_h264_is_duplicated_pps_error(ret) | ||
| 1679 | - ) { | ||
| 1680 | - continue; | ||
| 1681 | - } | 1664 | + SrsAmf0EcmaArray* obj = (SrsAmf0EcmaArray*)amf0; |
| 1665 | + return (srs_amf0_t)obj->value_at(index); | ||
| 1666 | +} | ||
| 1682 | 1667 | ||
| 1683 | - return ret; | ||
| 1684 | - } | ||
| 1685 | - } | 1668 | +srs_amf0_t srs_amf0_ecma_array_property(srs_amf0_t amf0, const char* name) |
| 1669 | +{ | ||
| 1670 | + SrsAmf0Any* any = (SrsAmf0Any*)amf0; | ||
| 1671 | + srs_assert(any->is_ecma_array()); | ||
| 1686 | 1672 | ||
| 1687 | - return error_code_return; | 1673 | + SrsAmf0EcmaArray* obj = (SrsAmf0EcmaArray*)amf0; |
| 1674 | + return (srs_amf0_t)obj->get_property(name); | ||
| 1688 | } | 1675 | } |
| 1689 | 1676 | ||
| 1690 | -srs_h264_bool srs_h264_is_dvbsp_error(int error_code) | 1677 | +void srs_amf0_ecma_array_property_set(srs_amf0_t amf0, const char* name, srs_amf0_t value) |
| 1691 | { | 1678 | { |
| 1692 | - return error_code == ERROR_H264_DROP_BEFORE_SPS_PPS; | 1679 | + SrsAmf0Any* any = (SrsAmf0Any*)amf0; |
| 1680 | + srs_assert(any->is_ecma_array()); | ||
| 1681 | + | ||
| 1682 | + SrsAmf0EcmaArray* obj = (SrsAmf0EcmaArray*)amf0; | ||
| 1683 | + any = (SrsAmf0Any*)value; | ||
| 1684 | + obj->set(name, any); | ||
| 1693 | } | 1685 | } |
| 1694 | 1686 | ||
| 1695 | -srs_h264_bool srs_h264_is_duplicated_sps_error(int error_code) | 1687 | +int srs_amf0_strict_array_property_count(srs_amf0_t amf0) |
| 1696 | { | 1688 | { |
| 1697 | - return error_code == ERROR_H264_DUPLICATED_SPS; | 1689 | + SrsAmf0Any* any = (SrsAmf0Any*)amf0; |
| 1690 | + srs_assert(any->is_strict_array()); | ||
| 1691 | + | ||
| 1692 | + SrsAmf0StrictArray * obj = (SrsAmf0StrictArray*)amf0; | ||
| 1693 | + return obj->count(); | ||
| 1698 | } | 1694 | } |
| 1699 | 1695 | ||
| 1700 | -srs_h264_bool srs_h264_is_duplicated_pps_error(int error_code) | 1696 | +srs_amf0_t srs_amf0_strict_array_property_at(srs_amf0_t amf0, int index) |
| 1701 | { | 1697 | { |
| 1702 | - return error_code == ERROR_H264_DUPLICATED_PPS; | 1698 | + SrsAmf0Any* any = (SrsAmf0Any*)amf0; |
| 1699 | + srs_assert(any->is_strict_array()); | ||
| 1700 | + | ||
| 1701 | + SrsAmf0StrictArray* obj = (SrsAmf0StrictArray*)amf0; | ||
| 1702 | + return (srs_amf0_t)obj->at(index); | ||
| 1703 | } | 1703 | } |
| 1704 | 1704 | ||
| 1705 | -int srs_h264_startswith_annexb(char* h264_raw_data, int h264_raw_size, int* pnb_start_code) | 1705 | +void srs_amf0_strict_array_append(srs_amf0_t amf0, srs_amf0_t value) |
| 1706 | { | 1706 | { |
| 1707 | - SrsStream stream; | ||
| 1708 | - if (stream.initialize(h264_raw_data, h264_raw_size) != ERROR_SUCCESS) { | ||
| 1709 | - return false; | ||
| 1710 | - } | 1707 | + SrsAmf0Any* any = (SrsAmf0Any*)amf0; |
| 1708 | + srs_assert(any->is_strict_array()); | ||
| 1711 | 1709 | ||
| 1712 | - return srs_avc_startswith_annexb(&stream, pnb_start_code); | 1710 | + SrsAmf0StrictArray* obj = (SrsAmf0StrictArray*)amf0; |
| 1711 | + any = (SrsAmf0Any*)value; | ||
| 1712 | + obj->append(any); | ||
| 1713 | } | 1713 | } |
| 1714 | 1714 | ||
| 1715 | int64_t srs_utils_get_time_ms() | 1715 | int64_t srs_utils_get_time_ms() |
| @@ -264,164 +264,6 @@ extern int srs_rtmp_write_packet(srs_rtmp_t rtmp, | @@ -264,164 +264,6 @@ extern int srs_rtmp_write_packet(srs_rtmp_t rtmp, | ||
| 264 | 264 | ||
| 265 | /************************************************************* | 265 | /************************************************************* |
| 266 | ************************************************************** | 266 | ************************************************************** |
| 267 | -* flv codec | ||
| 268 | -* @example /trunk/research/librtmp/srs_flv_injecter.c | ||
| 269 | -* @example /trunk/research/librtmp/srs_flv_parser.c | ||
| 270 | -* @example /trunk/research/librtmp/srs_ingest_flv.c | ||
| 271 | -* @example /trunk/research/librtmp/srs_ingest_rtmp.c | ||
| 272 | -************************************************************** | ||
| 273 | -*************************************************************/ | ||
| 274 | -typedef void* srs_flv_t; | ||
| 275 | -typedef int srs_flv_bool; | ||
| 276 | -/* open flv file for both read/write. */ | ||
| 277 | -extern srs_flv_t srs_flv_open_read(const char* file); | ||
| 278 | -extern srs_flv_t srs_flv_open_write(const char* file); | ||
| 279 | -extern void srs_flv_close(srs_flv_t flv); | ||
| 280 | -/** | ||
| 281 | -* read the flv header. 9bytes header. | ||
| 282 | -* @param header, @see E.2 The FLV header, flv_v10_1.pdf in SRS doc. | ||
| 283 | -* 3bytes, signature, "FLV", | ||
| 284 | -* 1bytes, version, 0x01, | ||
| 285 | -* 1bytes, flags, UB[5] 0, UB[1] audio present, UB[1] 0, UB[1] video present. | ||
| 286 | -* 4bytes, dataoffset, 0x09, The length of this header in bytes | ||
| 287 | -* | ||
| 288 | -* @return 0, success; otherswise, failed. | ||
| 289 | -* @remark, drop the 4bytes zero previous tag size. | ||
| 290 | -*/ | ||
| 291 | -extern int srs_flv_read_header(srs_flv_t flv, char header[9]); | ||
| 292 | -/** | ||
| 293 | -* read the flv tag header, 1bytes tag, 3bytes data_size, | ||
| 294 | -* 4bytes time, 3bytes stream id. | ||
| 295 | -* @param ptype, output the type of tag, macros: | ||
| 296 | -* SRS_RTMP_TYPE_AUDIO, FlvTagAudio | ||
| 297 | -* SRS_RTMP_TYPE_VIDEO, FlvTagVideo | ||
| 298 | -* SRS_RTMP_TYPE_SCRIPT, FlvTagScript | ||
| 299 | -* @param pdata_size, output the size of tag data. | ||
| 300 | -* @param ptime, output the time of tag, the dts in ms. | ||
| 301 | -* | ||
| 302 | -* @return 0, success; otherswise, failed. | ||
| 303 | -* @remark, user must ensure the next is a tag, srs never check it. | ||
| 304 | -*/ | ||
| 305 | -extern int srs_flv_read_tag_header(srs_flv_t flv, | ||
| 306 | - char* ptype, int32_t* pdata_size, u_int32_t* ptime | ||
| 307 | -); | ||
| 308 | -/** | ||
| 309 | -* read the tag data. drop the 4bytes previous tag size | ||
| 310 | -* @param data, the data to read, user alloc and free it. | ||
| 311 | -* @param size, the size of data to read, get by srs_flv_read_tag_header(). | ||
| 312 | -* @remark, srs will ignore and drop the 4bytes previous tag size. | ||
| 313 | -*/ | ||
| 314 | -extern int srs_flv_read_tag_data(srs_flv_t flv, char* data, int32_t size); | ||
| 315 | -/** | ||
| 316 | -* write the flv header. 9bytes header. | ||
| 317 | -* @param header, @see E.2 The FLV header, flv_v10_1.pdf in SRS doc. | ||
| 318 | -* 3bytes, signature, "FLV", | ||
| 319 | -* 1bytes, version, 0x01, | ||
| 320 | -* 1bytes, flags, UB[5] 0, UB[1] audio present, UB[1] 0, UB[1] video present. | ||
| 321 | -* 4bytes, dataoffset, 0x09, The length of this header in bytes | ||
| 322 | -* | ||
| 323 | -* @return 0, success; otherswise, failed. | ||
| 324 | -* @remark, auto write the 4bytes zero previous tag size. | ||
| 325 | -*/ | ||
| 326 | -extern int srs_flv_write_header(srs_flv_t flv, char header[9]); | ||
| 327 | -/** | ||
| 328 | -* write the flv tag to file. | ||
| 329 | -* | ||
| 330 | -* @return 0, success; otherswise, failed. | ||
| 331 | -* @remark, auto write the 4bytes zero previous tag size. | ||
| 332 | -*/ | ||
| 333 | -/* write flv tag to file, auto write the 4bytes previous tag size */ | ||
| 334 | -extern int srs_flv_write_tag(srs_flv_t flv, | ||
| 335 | - char type, int32_t time, char* data, int size | ||
| 336 | -); | ||
| 337 | -/** | ||
| 338 | -* get the tag size, for flv injecter to adjust offset, | ||
| 339 | -* size = tag_header(11B) + data_size + previous_tag(4B) | ||
| 340 | -* @return the size of tag. | ||
| 341 | -*/ | ||
| 342 | -extern int srs_flv_size_tag(int data_size); | ||
| 343 | -/* file stream */ | ||
| 344 | -/* file stream tellg to get offset */ | ||
| 345 | -extern int64_t srs_flv_tellg(srs_flv_t flv); | ||
| 346 | -/* seek file stream, offset is form the start of file */ | ||
| 347 | -extern void srs_flv_lseek(srs_flv_t flv, int64_t offset); | ||
| 348 | -/* error code */ | ||
| 349 | -/* whether the error code indicates EOF */ | ||
| 350 | -extern srs_flv_bool srs_flv_is_eof(int error_code); | ||
| 351 | -/* media codec */ | ||
| 352 | -/** | ||
| 353 | -* whether the video body is sequence header | ||
| 354 | -* @param data, the data of tag, read by srs_flv_read_tag_data(). | ||
| 355 | -* @param size, the size of tag, read by srs_flv_read_tag_data(). | ||
| 356 | -*/ | ||
| 357 | -extern srs_flv_bool srs_flv_is_sequence_header(char* data, int32_t size); | ||
| 358 | -/** | ||
| 359 | -* whether the video body is keyframe | ||
| 360 | -* @param data, the data of tag, read by srs_flv_read_tag_data(). | ||
| 361 | -* @param size, the size of tag, read by srs_flv_read_tag_data(). | ||
| 362 | -*/ | ||
| 363 | -extern srs_flv_bool srs_flv_is_keyframe(char* data, int32_t size); | ||
| 364 | - | ||
| 365 | -/************************************************************* | ||
| 366 | -************************************************************** | ||
| 367 | -* amf0 codec | ||
| 368 | -* @example /trunk/research/librtmp/srs_ingest_flv.c | ||
| 369 | -* @example /trunk/research/librtmp/srs_ingest_rtmp.c | ||
| 370 | -************************************************************** | ||
| 371 | -*************************************************************/ | ||
| 372 | -/* the output handler. */ | ||
| 373 | -typedef void* srs_amf0_t; | ||
| 374 | -typedef int srs_amf0_bool; | ||
| 375 | -typedef double srs_amf0_number; | ||
| 376 | -/** | ||
| 377 | -* parse amf0 from data. | ||
| 378 | -* @param nparsed, the parsed size, NULL to ignore. | ||
| 379 | -* @return the parsed amf0 object. NULL for error. | ||
| 380 | -*/ | ||
| 381 | -extern srs_amf0_t srs_amf0_parse(char* data, int size, int* nparsed); | ||
| 382 | -extern srs_amf0_t srs_amf0_create_number(srs_amf0_number value); | ||
| 383 | -extern srs_amf0_t srs_amf0_create_ecma_array(); | ||
| 384 | -extern srs_amf0_t srs_amf0_create_strict_array(); | ||
| 385 | -extern srs_amf0_t srs_amf0_create_object(); | ||
| 386 | -extern void srs_amf0_free(srs_amf0_t amf0); | ||
| 387 | -extern void srs_amf0_free_bytes(char* data); | ||
| 388 | -/* size and to bytes */ | ||
| 389 | -extern int srs_amf0_size(srs_amf0_t amf0); | ||
| 390 | -extern int srs_amf0_serialize(srs_amf0_t amf0, char* data, int size); | ||
| 391 | -/* type detecter */ | ||
| 392 | -extern srs_amf0_bool srs_amf0_is_string(srs_amf0_t amf0); | ||
| 393 | -extern srs_amf0_bool srs_amf0_is_boolean(srs_amf0_t amf0); | ||
| 394 | -extern srs_amf0_bool srs_amf0_is_number(srs_amf0_t amf0); | ||
| 395 | -extern srs_amf0_bool srs_amf0_is_null(srs_amf0_t amf0); | ||
| 396 | -extern srs_amf0_bool srs_amf0_is_object(srs_amf0_t amf0); | ||
| 397 | -extern srs_amf0_bool srs_amf0_is_ecma_array(srs_amf0_t amf0); | ||
| 398 | -extern srs_amf0_bool srs_amf0_is_strict_array(srs_amf0_t amf0); | ||
| 399 | -/* value converter */ | ||
| 400 | -extern const char* srs_amf0_to_string(srs_amf0_t amf0); | ||
| 401 | -extern srs_amf0_bool srs_amf0_to_boolean(srs_amf0_t amf0); | ||
| 402 | -extern srs_amf0_number srs_amf0_to_number(srs_amf0_t amf0); | ||
| 403 | -/* value setter */ | ||
| 404 | -extern void srs_amf0_set_number(srs_amf0_t amf0, srs_amf0_number value); | ||
| 405 | -/* object value converter */ | ||
| 406 | -extern int srs_amf0_object_property_count(srs_amf0_t amf0); | ||
| 407 | -extern const char* srs_amf0_object_property_name_at(srs_amf0_t amf0, int index); | ||
| 408 | -extern srs_amf0_t srs_amf0_object_property_value_at(srs_amf0_t amf0, int index); | ||
| 409 | -extern srs_amf0_t srs_amf0_object_property(srs_amf0_t amf0, const char* name); | ||
| 410 | -extern void srs_amf0_object_property_set(srs_amf0_t amf0, const char* name, srs_amf0_t value); | ||
| 411 | -extern void srs_amf0_object_clear(srs_amf0_t amf0); | ||
| 412 | -/* ecma array value converter */ | ||
| 413 | -extern int srs_amf0_ecma_array_property_count(srs_amf0_t amf0); | ||
| 414 | -extern const char* srs_amf0_ecma_array_property_name_at(srs_amf0_t amf0, int index); | ||
| 415 | -extern srs_amf0_t srs_amf0_ecma_array_property_value_at(srs_amf0_t amf0, int index); | ||
| 416 | -extern srs_amf0_t srs_amf0_ecma_array_property(srs_amf0_t amf0, const char* name); | ||
| 417 | -extern void srs_amf0_ecma_array_property_set(srs_amf0_t amf0, const char* name, srs_amf0_t value); | ||
| 418 | -/* strict array value converter */ | ||
| 419 | -extern int srs_amf0_strict_array_property_count(srs_amf0_t amf0); | ||
| 420 | -extern srs_amf0_t srs_amf0_strict_array_property_at(srs_amf0_t amf0, int index); | ||
| 421 | -extern void srs_amf0_strict_array_append(srs_amf0_t amf0, srs_amf0_t value); | ||
| 422 | - | ||
| 423 | -/************************************************************* | ||
| 424 | -************************************************************** | ||
| 425 | * audio raw codec | 267 | * audio raw codec |
| 426 | ************************************************************** | 268 | ************************************************************** |
| 427 | *************************************************************/ | 269 | *************************************************************/ |
| @@ -585,6 +427,164 @@ extern int srs_h264_startswith_annexb( | @@ -585,6 +427,164 @@ extern int srs_h264_startswith_annexb( | ||
| 585 | 427 | ||
| 586 | /************************************************************* | 428 | /************************************************************* |
| 587 | ************************************************************** | 429 | ************************************************************** |
| 430 | +* flv codec | ||
| 431 | +* @example /trunk/research/librtmp/srs_flv_injecter.c | ||
| 432 | +* @example /trunk/research/librtmp/srs_flv_parser.c | ||
| 433 | +* @example /trunk/research/librtmp/srs_ingest_flv.c | ||
| 434 | +* @example /trunk/research/librtmp/srs_ingest_rtmp.c | ||
| 435 | +************************************************************** | ||
| 436 | +*************************************************************/ | ||
| 437 | +typedef void* srs_flv_t; | ||
| 438 | +typedef int srs_flv_bool; | ||
| 439 | +/* open flv file for both read/write. */ | ||
| 440 | +extern srs_flv_t srs_flv_open_read(const char* file); | ||
| 441 | +extern srs_flv_t srs_flv_open_write(const char* file); | ||
| 442 | +extern void srs_flv_close(srs_flv_t flv); | ||
| 443 | +/** | ||
| 444 | +* read the flv header. 9bytes header. | ||
| 445 | +* @param header, @see E.2 The FLV header, flv_v10_1.pdf in SRS doc. | ||
| 446 | +* 3bytes, signature, "FLV", | ||
| 447 | +* 1bytes, version, 0x01, | ||
| 448 | +* 1bytes, flags, UB[5] 0, UB[1] audio present, UB[1] 0, UB[1] video present. | ||
| 449 | +* 4bytes, dataoffset, 0x09, The length of this header in bytes | ||
| 450 | +* | ||
| 451 | +* @return 0, success; otherswise, failed. | ||
| 452 | +* @remark, drop the 4bytes zero previous tag size. | ||
| 453 | +*/ | ||
| 454 | +extern int srs_flv_read_header(srs_flv_t flv, char header[9]); | ||
| 455 | +/** | ||
| 456 | +* read the flv tag header, 1bytes tag, 3bytes data_size, | ||
| 457 | +* 4bytes time, 3bytes stream id. | ||
| 458 | +* @param ptype, output the type of tag, macros: | ||
| 459 | +* SRS_RTMP_TYPE_AUDIO, FlvTagAudio | ||
| 460 | +* SRS_RTMP_TYPE_VIDEO, FlvTagVideo | ||
| 461 | +* SRS_RTMP_TYPE_SCRIPT, FlvTagScript | ||
| 462 | +* @param pdata_size, output the size of tag data. | ||
| 463 | +* @param ptime, output the time of tag, the dts in ms. | ||
| 464 | +* | ||
| 465 | +* @return 0, success; otherswise, failed. | ||
| 466 | +* @remark, user must ensure the next is a tag, srs never check it. | ||
| 467 | +*/ | ||
| 468 | +extern int srs_flv_read_tag_header(srs_flv_t flv, | ||
| 469 | + char* ptype, int32_t* pdata_size, u_int32_t* ptime | ||
| 470 | +); | ||
| 471 | +/** | ||
| 472 | +* read the tag data. drop the 4bytes previous tag size | ||
| 473 | +* @param data, the data to read, user alloc and free it. | ||
| 474 | +* @param size, the size of data to read, get by srs_flv_read_tag_header(). | ||
| 475 | +* @remark, srs will ignore and drop the 4bytes previous tag size. | ||
| 476 | +*/ | ||
| 477 | +extern int srs_flv_read_tag_data(srs_flv_t flv, char* data, int32_t size); | ||
| 478 | +/** | ||
| 479 | +* write the flv header. 9bytes header. | ||
| 480 | +* @param header, @see E.2 The FLV header, flv_v10_1.pdf in SRS doc. | ||
| 481 | +* 3bytes, signature, "FLV", | ||
| 482 | +* 1bytes, version, 0x01, | ||
| 483 | +* 1bytes, flags, UB[5] 0, UB[1] audio present, UB[1] 0, UB[1] video present. | ||
| 484 | +* 4bytes, dataoffset, 0x09, The length of this header in bytes | ||
| 485 | +* | ||
| 486 | +* @return 0, success; otherswise, failed. | ||
| 487 | +* @remark, auto write the 4bytes zero previous tag size. | ||
| 488 | +*/ | ||
| 489 | +extern int srs_flv_write_header(srs_flv_t flv, char header[9]); | ||
| 490 | +/** | ||
| 491 | +* write the flv tag to file. | ||
| 492 | +* | ||
| 493 | +* @return 0, success; otherswise, failed. | ||
| 494 | +* @remark, auto write the 4bytes zero previous tag size. | ||
| 495 | +*/ | ||
| 496 | +/* write flv tag to file, auto write the 4bytes previous tag size */ | ||
| 497 | +extern int srs_flv_write_tag(srs_flv_t flv, | ||
| 498 | + char type, int32_t time, char* data, int size | ||
| 499 | +); | ||
| 500 | +/** | ||
| 501 | +* get the tag size, for flv injecter to adjust offset, | ||
| 502 | +* size = tag_header(11B) + data_size + previous_tag(4B) | ||
| 503 | +* @return the size of tag. | ||
| 504 | +*/ | ||
| 505 | +extern int srs_flv_size_tag(int data_size); | ||
| 506 | +/* file stream */ | ||
| 507 | +/* file stream tellg to get offset */ | ||
| 508 | +extern int64_t srs_flv_tellg(srs_flv_t flv); | ||
| 509 | +/* seek file stream, offset is form the start of file */ | ||
| 510 | +extern void srs_flv_lseek(srs_flv_t flv, int64_t offset); | ||
| 511 | +/* error code */ | ||
| 512 | +/* whether the error code indicates EOF */ | ||
| 513 | +extern srs_flv_bool srs_flv_is_eof(int error_code); | ||
| 514 | +/* media codec */ | ||
| 515 | +/** | ||
| 516 | +* whether the video body is sequence header | ||
| 517 | +* @param data, the data of tag, read by srs_flv_read_tag_data(). | ||
| 518 | +* @param size, the size of tag, read by srs_flv_read_tag_data(). | ||
| 519 | +*/ | ||
| 520 | +extern srs_flv_bool srs_flv_is_sequence_header(char* data, int32_t size); | ||
| 521 | +/** | ||
| 522 | +* whether the video body is keyframe | ||
| 523 | +* @param data, the data of tag, read by srs_flv_read_tag_data(). | ||
| 524 | +* @param size, the size of tag, read by srs_flv_read_tag_data(). | ||
| 525 | +*/ | ||
| 526 | +extern srs_flv_bool srs_flv_is_keyframe(char* data, int32_t size); | ||
| 527 | + | ||
| 528 | +/************************************************************* | ||
| 529 | +************************************************************** | ||
| 530 | +* amf0 codec | ||
| 531 | +* @example /trunk/research/librtmp/srs_ingest_flv.c | ||
| 532 | +* @example /trunk/research/librtmp/srs_ingest_rtmp.c | ||
| 533 | +************************************************************** | ||
| 534 | +*************************************************************/ | ||
| 535 | +/* the output handler. */ | ||
| 536 | +typedef void* srs_amf0_t; | ||
| 537 | +typedef int srs_amf0_bool; | ||
| 538 | +typedef double srs_amf0_number; | ||
| 539 | +/** | ||
| 540 | +* parse amf0 from data. | ||
| 541 | +* @param nparsed, the parsed size, NULL to ignore. | ||
| 542 | +* @return the parsed amf0 object. NULL for error. | ||
| 543 | +*/ | ||
| 544 | +extern srs_amf0_t srs_amf0_parse(char* data, int size, int* nparsed); | ||
| 545 | +extern srs_amf0_t srs_amf0_create_number(srs_amf0_number value); | ||
| 546 | +extern srs_amf0_t srs_amf0_create_ecma_array(); | ||
| 547 | +extern srs_amf0_t srs_amf0_create_strict_array(); | ||
| 548 | +extern srs_amf0_t srs_amf0_create_object(); | ||
| 549 | +extern void srs_amf0_free(srs_amf0_t amf0); | ||
| 550 | +extern void srs_amf0_free_bytes(char* data); | ||
| 551 | +/* size and to bytes */ | ||
| 552 | +extern int srs_amf0_size(srs_amf0_t amf0); | ||
| 553 | +extern int srs_amf0_serialize(srs_amf0_t amf0, char* data, int size); | ||
| 554 | +/* type detecter */ | ||
| 555 | +extern srs_amf0_bool srs_amf0_is_string(srs_amf0_t amf0); | ||
| 556 | +extern srs_amf0_bool srs_amf0_is_boolean(srs_amf0_t amf0); | ||
| 557 | +extern srs_amf0_bool srs_amf0_is_number(srs_amf0_t amf0); | ||
| 558 | +extern srs_amf0_bool srs_amf0_is_null(srs_amf0_t amf0); | ||
| 559 | +extern srs_amf0_bool srs_amf0_is_object(srs_amf0_t amf0); | ||
| 560 | +extern srs_amf0_bool srs_amf0_is_ecma_array(srs_amf0_t amf0); | ||
| 561 | +extern srs_amf0_bool srs_amf0_is_strict_array(srs_amf0_t amf0); | ||
| 562 | +/* value converter */ | ||
| 563 | +extern const char* srs_amf0_to_string(srs_amf0_t amf0); | ||
| 564 | +extern srs_amf0_bool srs_amf0_to_boolean(srs_amf0_t amf0); | ||
| 565 | +extern srs_amf0_number srs_amf0_to_number(srs_amf0_t amf0); | ||
| 566 | +/* value setter */ | ||
| 567 | +extern void srs_amf0_set_number(srs_amf0_t amf0, srs_amf0_number value); | ||
| 568 | +/* object value converter */ | ||
| 569 | +extern int srs_amf0_object_property_count(srs_amf0_t amf0); | ||
| 570 | +extern const char* srs_amf0_object_property_name_at(srs_amf0_t amf0, int index); | ||
| 571 | +extern srs_amf0_t srs_amf0_object_property_value_at(srs_amf0_t amf0, int index); | ||
| 572 | +extern srs_amf0_t srs_amf0_object_property(srs_amf0_t amf0, const char* name); | ||
| 573 | +extern void srs_amf0_object_property_set(srs_amf0_t amf0, const char* name, srs_amf0_t value); | ||
| 574 | +extern void srs_amf0_object_clear(srs_amf0_t amf0); | ||
| 575 | +/* ecma array value converter */ | ||
| 576 | +extern int srs_amf0_ecma_array_property_count(srs_amf0_t amf0); | ||
| 577 | +extern const char* srs_amf0_ecma_array_property_name_at(srs_amf0_t amf0, int index); | ||
| 578 | +extern srs_amf0_t srs_amf0_ecma_array_property_value_at(srs_amf0_t amf0, int index); | ||
| 579 | +extern srs_amf0_t srs_amf0_ecma_array_property(srs_amf0_t amf0, const char* name); | ||
| 580 | +extern void srs_amf0_ecma_array_property_set(srs_amf0_t amf0, const char* name, srs_amf0_t value); | ||
| 581 | +/* strict array value converter */ | ||
| 582 | +extern int srs_amf0_strict_array_property_count(srs_amf0_t amf0); | ||
| 583 | +extern srs_amf0_t srs_amf0_strict_array_property_at(srs_amf0_t amf0, int index); | ||
| 584 | +extern void srs_amf0_strict_array_append(srs_amf0_t amf0, srs_amf0_t value); | ||
| 585 | + | ||
| 586 | +/************************************************************* | ||
| 587 | +************************************************************** | ||
| 588 | * utilities | 588 | * utilities |
| 589 | ************************************************************** | 589 | ************************************************************** |
| 590 | *************************************************************/ | 590 | *************************************************************/ |
-
请 注册 或 登录 后发表评论